summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/painting.pri177
-rw-r--r--src/gui/painting/qbackingstore.cpp159
-rw-r--r--src/gui/painting/qbackingstore.h40
-rw-r--r--src/gui/painting/qbackingstoredefaultcompositor.cpp676
-rw-r--r--src/gui/painting/qbackingstoredefaultcompositor_p.h110
-rw-r--r--src/gui/painting/qbackingstorerhisupport.cpp327
-rw-r--r--src/gui/painting/qbackingstorerhisupport_p.h77
-rw-r--r--src/gui/painting/qbezier.cpp62
-rw-r--r--src/gui/painting/qbezier_p.h41
-rw-r--r--src/gui/painting/qblendfunctions.cpp50
-rw-r--r--src/gui/painting/qblendfunctions_p.h97
-rw-r--r--src/gui/painting/qblittable.cpp40
-rw-r--r--src/gui/painting/qblittable_p.h40
-rw-r--r--src/gui/painting/qbrush.cpp393
-rw-r--r--src/gui/painting/qbrush.h65
-rw-r--r--src/gui/painting/qcmyk_p.h88
-rw-r--r--src/gui/painting/qcolor.cpp696
-rw-r--r--src/gui/painting/qcolor.h505
-rw-r--r--src/gui/painting/qcolor_p.h44
-rw-r--r--src/gui/painting/qcolorclut_p.h127
-rw-r--r--src/gui/painting/qcolormatrix_p.h297
-rw-r--r--src/gui/painting/qcolorspace.cpp961
-rw-r--r--src/gui/painting/qcolorspace.h124
-rw-r--r--src/gui/painting/qcolorspace_p.h110
-rw-r--r--src/gui/painting/qcolortransferfunction_p.h116
-rw-r--r--src/gui/painting/qcolortransfertable_p.h193
-rw-r--r--src/gui/painting/qcolortransform.cpp1748
-rw-r--r--src/gui/painting/qcolortransform.h76
-rw-r--r--src/gui/painting/qcolortransform_p.h72
-rw-r--r--src/gui/painting/qcolortrc_p.h61
-rw-r--r--src/gui/painting/qcolortrclut.cpp126
-rw-r--r--src/gui/painting/qcolortrclut_p.h132
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp1330
-rw-r--r--src/gui/painting/qcoregraphics.mm95
-rw-r--r--src/gui/painting/qcoregraphics_p.h64
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp154
-rw-r--r--src/gui/painting/qcosmeticstroker_p.h45
-rw-r--r--src/gui/painting/qcssutil.cpp65
-rw-r--r--src/gui/painting/qcssutil_p.h40
-rw-r--r--src/gui/painting/qdatabuffer_p.h64
-rw-r--r--src/gui/painting/qdrawhelper.cpp2739
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp480
-rw-r--r--src/gui/painting/qdrawhelper_mips_dsp.cpp44
-rw-r--r--src/gui/painting/qdrawhelper_mips_dsp_asm.S42
-rw-r--r--src/gui/painting/qdrawhelper_mips_dsp_p.h40
-rw-r--r--src/gui/painting/qdrawhelper_mips_dspr2_asm.S40
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp70
-rw-r--r--src/gui/painting/qdrawhelper_neon_asm.S42
-rw-r--r--src/gui/painting/qdrawhelper_neon_p.h40
-rw-r--r--src/gui/painting/qdrawhelper_p.h248
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp121
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp251
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp44
-rw-r--r--src/gui/painting/qdrawhelper_x86_p.h40
-rw-r--r--src/gui/painting/qdrawingprimitive_sse2_p.h54
-rw-r--r--src/gui/painting/qemulationpaintengine.cpp44
-rw-r--r--src/gui/painting/qemulationpaintengine_p.h40
-rw-r--r--src/gui/painting/qfixed_p.h207
-rw-r--r--src/gui/painting/qgrayraster.c236
-rw-r--r--src/gui/painting/qgrayraster_p.h40
-rw-r--r--src/gui/painting/qicc.cpp1147
-rw-r--r--src/gui/painting/qicc_p.h41
-rw-r--r--src/gui/painting/qimageeffects.cpp327
-rw-r--r--src/gui/painting/qimagescale.cpp274
-rw-r--r--src/gui/painting/qimagescale_neon.cpp49
-rw-r--r--src/gui/painting/qimagescale_p.h41
-rw-r--r--src/gui/painting/qimagescale_sse4.cpp49
-rw-r--r--src/gui/painting/qmath_p.h56
-rw-r--r--src/gui/painting/qmemrotate.cpp146
-rw-r--r--src/gui/painting/qmemrotate_p.h40
-rw-r--r--src/gui/painting/qoutlinemapper.cpp74
-rw-r--r--src/gui/painting/qoutlinemapper_p.h56
-rw-r--r--src/gui/painting/qpagedpaintdevice.cpp356
-rw-r--r--src/gui/painting/qpagedpaintdevice.h225
-rw-r--r--src/gui/painting/qpagedpaintdevice_p.h46
-rw-r--r--src/gui/painting/qpagelayout.cpp267
-rw-r--r--src/gui/painting/qpagelayout.h78
-rw-r--r--src/gui/painting/qpageranges.cpp367
-rw-r--r--src/gui/painting/qpageranges.h89
-rw-r--r--src/gui/painting/qpageranges_p.h33
-rw-r--r--src/gui/painting/qpagesize.cpp99
-rw-r--r--src/gui/painting/qpagesize.h79
-rw-r--r--src/gui/painting/qpaintdevice.cpp41
-rw-r--r--src/gui/painting/qpaintdevice.h47
-rw-r--r--src/gui/painting/qpaintdevice.qdoc32
-rw-r--r--src/gui/painting/qpaintengine.cpp92
-rw-r--r--src/gui/painting/qpaintengine.h50
-rw-r--r--src/gui/painting/qpaintengine_blitter.cpp40
-rw-r--r--src/gui/painting/qpaintengine_blitter_p.h40
-rw-r--r--src/gui/painting/qpaintengine_p.h40
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp525
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h63
-rw-r--r--src/gui/painting/qpaintengineex.cpp100
-rw-r--r--src/gui/painting/qpaintengineex_p.h40
-rw-r--r--src/gui/painting/qpainter.cpp428
-rw-r--r--src/gui/painting/qpainter.h78
-rw-r--r--src/gui/painting/qpainter_p.h98
-rw-r--r--src/gui/painting/qpainterpath.cpp164
-rw-r--r--src/gui/painting/qpainterpath.h66
-rw-r--r--src/gui/painting/qpainterpath_p.h181
-rw-r--r--src/gui/painting/qpathclipper.cpp64
-rw-r--r--src/gui/painting/qpathclipper_p.h52
-rw-r--r--src/gui/painting/qpathsimplifier.cpp62
-rw-r--r--src/gui/painting/qpathsimplifier_p.h40
-rw-r--r--src/gui/painting/qpdf.cpp714
-rw-r--r--src/gui/painting/qpdf.qrc7
-rw-r--r--src/gui/painting/qpdf_p.h111
-rw-r--r--src/gui/painting/qpdfwriter.cpp227
-rw-r--r--src/gui/painting/qpdfwriter.h70
-rw-r--r--src/gui/painting/qpen.cpp216
-rw-r--r--src/gui/painting/qpen.h59
-rw-r--r--src/gui/painting/qpen_p.h52
-rw-r--r--src/gui/painting/qpixellayout.cpp1587
-rw-r--r--src/gui/painting/qpixellayout_p.h87
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp245
-rw-r--r--src/gui/painting/qplatformbackingstore.h163
-rw-r--r--src/gui/painting/qpolygon.cpp178
-rw-r--r--src/gui/painting/qpolygon.h149
-rw-r--r--src/gui/painting/qpolygonclipper_p.h316
-rw-r--r--src/gui/painting/qrangecollection.cpp281
-rw-r--r--src/gui/painting/qrangecollection.h78
-rw-r--r--src/gui/painting/qrangecollection_p.h76
-rw-r--r--src/gui/painting/qrasterbackingstore.cpp48
-rw-r--r--src/gui/painting/qrasterbackingstore_p.h41
-rw-r--r--src/gui/painting/qrasterdefs_p.h48
-rw-r--r--src/gui/painting/qrasterizer.cpp595
-rw-r--r--src/gui/painting/qrasterizer_p.h41
-rw-r--r--src/gui/painting/qrbtree_p.h40
-rw-r--r--src/gui/painting/qregion.cpp142
-rw-r--r--src/gui/painting/qregion.h69
-rw-r--r--src/gui/painting/qrgb.h62
-rw-r--r--src/gui/painting/qrgba64.h110
-rw-r--r--src/gui/painting/qrgba64.qdoc28
-rw-r--r--src/gui/painting/qrgba64_p.h219
-rw-r--r--src/gui/painting/qrgbafloat.h126
-rw-r--r--src/gui/painting/qrgbafloat.qdoc241
-rw-r--r--src/gui/painting/qrhibackingstore.cpp68
-rw-r--r--src/gui/painting/qrhibackingstore_p.h34
-rw-r--r--src/gui/painting/qstroker.cpp106
-rw-r--r--src/gui/painting/qstroker_p.h49
-rw-r--r--src/gui/painting/qt_attribution.json16
-rw-r--r--src/gui/painting/qt_mips_asm_dsp_p.h46
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp79
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h72
-rw-r--r--src/gui/painting/qtransform.cpp359
-rw-r--r--src/gui/painting/qtransform.h57
-rw-r--r--src/gui/painting/qtriangulatingstroker.cpp51
-rw-r--r--src/gui/painting/qtriangulatingstroker_p.h56
-rw-r--r--src/gui/painting/qtriangulator.cpp69
-rw-r--r--src/gui/painting/qtriangulator_p.h40
-rw-r--r--src/gui/painting/qvectorpath_p.h40
-rw-r--r--src/gui/painting/shaders/backingstorecompose.frag25
-rw-r--r--src/gui/painting/shaders/backingstorecompose.frag.qsbbin0 -> 1657 bytes
-rw-r--r--src/gui/painting/shaders/backingstorecompose.vert19
-rw-r--r--src/gui/painting/shaders/backingstorecompose.vert.qsbbin0 -> 1408 bytes
-rw-r--r--src/gui/painting/webgradients.cpp55
156 files changed, 16566 insertions, 11932 deletions
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
deleted file mode 100644
index 52729d8f09..0000000000
--- a/src/gui/painting/painting.pri
+++ /dev/null
@@ -1,177 +0,0 @@
-# Qt gui library, paint module
-
-HEADERS += \
- painting/qbackingstore.h \
- painting/qbezier_p.h \
- painting/qblendfunctions_p.h \
- painting/qblittable_p.h \
- painting/qbrush.h \
- painting/qcolor.h \
- painting/qcolor_p.h \
- painting/qcolormatrix_p.h \
- painting/qcolorspace.h \
- painting/qcolorspace_p.h \
- painting/qcolortransferfunction_p.h \
- painting/qcolortransfertable_p.h \
- painting/qcolortransform.h \
- painting/qcolortransform_p.h \
- painting/qcolortrc_p.h \
- painting/qcolortrclut_p.h \
- painting/qcosmeticstroker_p.h \
- painting/qdatabuffer_p.h \
- painting/qdrawhelper_p.h \
- painting/qdrawhelper_x86_p.h \
- painting/qdrawingprimitive_sse2_p.h \
- painting/qemulationpaintengine_p.h \
- painting/qfixed_p.h \
- painting/qgrayraster_p.h \
- painting/qicc_p.h \
- painting/qmemrotate_p.h \
- painting/qoutlinemapper_p.h \
- painting/qpagedpaintdevice.h \
- painting/qpagedpaintdevice_p.h \
- painting/qpagelayout.h \
- painting/qpagesize.h \
- painting/qpaintdevice.h \
- painting/qpaintengine.h \
- painting/qpaintengine_p.h \
- painting/qpaintengineex_p.h \
- painting/qpaintengine_blitter_p.h \
- painting/qpaintengine_raster_p.h \
- painting/qpainter.h \
- painting/qpainter_p.h \
- painting/qpainterpath.h \
- painting/qpainterpath_p.h \
- painting/qvectorpath_p.h \
- painting/qpathclipper_p.h \
- painting/qpdf_p.h \
- painting/qpdfwriter.h \
- painting/qpen.h \
- painting/qpixellayout_p.h \
- painting/qpolygon.h \
- painting/qpolygonclipper_p.h \
- painting/qrangecollection.h \
- painting/qrangecollection_p.h \
- painting/qrasterdefs_p.h \
- painting/qrasterizer_p.h \
- painting/qrbtree_p.h \
- painting/qregion.h \
- painting/qrgb.h \
- painting/qrgba64.h \
- painting/qrgba64_p.h \
- painting/qstroker_p.h \
- painting/qtextureglyphcache_p.h \
- painting/qtransform.h \
- painting/qtriangulatingstroker_p.h \
- painting/qtriangulator_p.h \
- painting/qplatformbackingstore.h \
- painting/qpathsimplifier_p.h
-
-
-SOURCES += \
- painting/qbackingstore.cpp \
- painting/qbezier.cpp \
- painting/qblendfunctions.cpp \
- painting/qblittable.cpp \
- painting/qbrush.cpp \
- painting/qcolor.cpp \
- painting/qcolorspace.cpp \
- painting/qcolortransform.cpp \
- painting/qcolortrclut.cpp \
- painting/qcompositionfunctions.cpp \
- painting/qcosmeticstroker.cpp \
- painting/qdrawhelper.cpp \
- painting/qemulationpaintengine.cpp \
- painting/qgrayraster.c \
- painting/qicc.cpp \
- painting/qimagescale.cpp \
- painting/qmemrotate.cpp \
- painting/qoutlinemapper.cpp \
- painting/qpagedpaintdevice.cpp \
- painting/qpagelayout.cpp \
- painting/qpagesize.cpp \
- painting/qpaintdevice.cpp \
- painting/qpaintengine.cpp \
- painting/qpaintengineex.cpp \
- painting/qpaintengine_blitter.cpp \
- painting/qpaintengine_raster.cpp \
- painting/qpainter.cpp \
- painting/qpainterpath.cpp \
- painting/qpathclipper.cpp \
- painting/qpdf.cpp \
- painting/qpdfwriter.cpp \
- painting/qpen.cpp \
- painting/qpixellayout.cpp \
- painting/qpolygon.cpp \
- painting/qrangecollection.cpp \
- painting/qrasterizer.cpp \
- painting/qregion.cpp \
- painting/qstroker.cpp \
- painting/qtextureglyphcache.cpp \
- painting/qtransform.cpp \
- painting/qtriangulatingstroker.cpp \
- painting/qtriangulator.cpp \
- painting/qplatformbackingstore.cpp \
- painting/qpathsimplifier.cpp
-
-RESOURCES += \
- painting/qpdf.qrc \
-
-darwin {
- HEADERS += \
- painting/qcoregraphics_p.h \
- painting/qrasterbackingstore_p.h
- SOURCES += \
- painting/qcoregraphics.mm \
- painting/qrasterbackingstore.cpp
-}
-
-qtConfig(cssparser) {
- SOURCES += \
- painting/qcssutil.cpp
-}
-
-# Causes internal compiler errors with at least GCC 5.3.1:
-gcc:equals(QT_GCC_MAJOR_VERSION, 5) {
- SOURCES -= painting/qdrawhelper.cpp
- NO_PCH_SOURCES += painting/qdrawhelper.cpp
-}
-
-!android {
- SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
- SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp
- SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \
- painting/qimagescale_sse4.cpp
- ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp
-
- NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp
- NEON_HEADERS += painting/qdrawhelper_neon_p.h
-}
-!uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as
-!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") {
- NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S
- DEFINES += ENABLE_PIXMAN_DRAWHELPERS
-}
-
-!android {
- MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp
- MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h
- MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S
- MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S
-} else {
- # see https://developer.android.com/ndk/guides/abis
- x86 | x86_64 {
- DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3
- SOURCES += painting/qdrawhelper_sse2.cpp painting/qdrawhelper_ssse3.cpp
- }
- x86_64 {
- DEFINES += QT_COMPILER_SUPPORTS_SSE4_1 QT_COMPILER_SUPPORTS_SSE4_2
- SOURCES += painting/qdrawhelper_sse4.cpp painting/qimagescale_sse4.cpp
- }
- arm64-v8a | armeabi-v7a {
- SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp
- HEADERS += painting/qdrawhelper_neon_p.h
- }
-}
-
-include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 5bbc03db80..2304ee2256 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qbackingstore.h>
#include <qwindow.h>
@@ -61,11 +25,32 @@ public:
{
}
+ // Returns the DPR for the backing store. This is the DPR for the QWindow,
+ // possibly rounded up to the nearest integer.
+ qreal backingStoreDevicePixelRatio() const
+ {
+ // Note: keep in sync with QWidget::metric()!
+ qreal windowDpr = window->devicePixelRatio();
+ return downscale ? std::ceil(windowDpr) : windowDpr;
+ }
+
+ // Returns the factor used for converting from device independent to native
+ // backing store sizes. Normally this is just the gui scale factor, however
+ // if the backing store rounds the DPR up to the nearest integer then we also
+ // need to account for the factor introduced by that rounding.
+ qreal deviceIndependentToNativeFactor() const
+ {
+ const qreal roundingFactor = backingStoreDevicePixelRatio() / window->devicePixelRatio();
+ const qreal guiFactor = QHighDpiScaling::factor(window);
+ return roundingFactor * guiFactor;
+ }
+
QWindow *window;
QPlatformBackingStore *platformBackingStore = nullptr;
QScopedPointer<QImage> highDpiBackingstore;
QRegion staticContents;
QSize size;
+ bool downscale = qEnvironmentVariableIntValue("QT_WIDGETS_HIGHDPI_DOWNSCALE") > 0;
};
/*!
@@ -130,12 +115,14 @@ QWindow* QBackingStore::window() const
void QBackingStore::beginPaint(const QRegion &region)
{
+ const qreal dpr = d_ptr->backingStoreDevicePixelRatio();
+
if (d_ptr->highDpiBackingstore &&
- d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio())
+ d_ptr->highDpiBackingstore->devicePixelRatio() != dpr)
resize(size());
QPlatformBackingStore *platformBackingStore = handle();
- platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window));
+ platformBackingStore->beginPaint(QHighDpi::scale(region, d_ptr->deviceIndependentToNativeFactor()));
// When QtGui is applying a high-dpi scale factor the backing store
// creates a "large" backing store image. This image needs to be
@@ -151,15 +138,10 @@ void QBackingStore::beginPaint(const QRegion &region)
|| source->size() != d_ptr->highDpiBackingstore->size()
|| source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio();
if (needsNewImage) {
- qCDebug(lcScaling) << "QBackingStore::beginPaint new backingstore for" << d_ptr->window;
- qCDebug(lcScaling) << " source size" << source->size() << "dpr" << source->devicePixelRatio();
d_ptr->highDpiBackingstore.reset(
new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));
- qreal targetDevicePixelRatio = d_ptr->window->devicePixelRatio();
- d_ptr->highDpiBackingstore->setDevicePixelRatio(targetDevicePixelRatio);
- qCDebug(lcScaling) <<" destination size" << d_ptr->highDpiBackingstore->size()
- << "dpr" << targetDevicePixelRatio;
+ d_ptr->highDpiBackingstore->setDevicePixelRatio(dpr);
}
}
}
@@ -196,17 +178,6 @@ void QBackingStore::endPaint()
handle()->endPaint();
}
-static bool isRasterSurface(QWindow *window)
-{
- switch (window->surfaceType()) {
- case QSurface::RasterSurface:
- case QSurface::RasterGLSurface:
- return true;
- default:
- return false;
- };
-}
-
/*!
Flushes the given \a region from the specified \a window onto the
screen.
@@ -233,24 +204,22 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
return;
}
- if (!isRasterSurface(window)) {
- qWarning() << "Attempted flush to non-raster surface" << window << "of type" << window->surfaceType()
- << (window->inherits("QWidgetWindow") ? "(consider using Qt::WA_PaintOnScreen to exclude "
- "from backingstore sync)" : "");
- return;
- }
-
-#ifdef QBACKINGSTORE_DEBUG
- if (window && window->isTopLevel() && !qt_window_private(window)->receivedExpose) {
- qWarning().nospace() << "QBackingStore::flush() called with non-exposed window "
- << window << ", behavior is undefined";
- }
-#endif
-
Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
- handle()->flush(window, QHighDpi::toNativeLocalRegion(region, window),
- QHighDpi::toNativeLocalPosition(offset, window));
+ const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
+
+ QRegion nativeRegion = QHighDpi::scale(region, toNativeFactor);
+ QPoint nativeOffset;
+ if (!offset.isNull()) {
+ nativeOffset = QHighDpi::scale(offset, toNativeFactor);
+ // Under fractional DPR, rounding of region and offset may accumulate to an off-by-one
+ QPoint topLeft = region.boundingRect().topLeft() + offset;
+ QPoint nativeTopLeft = QHighDpi::scale(topLeft, toNativeFactor);
+ QPoint diff = nativeTopLeft - (nativeRegion.boundingRect().topLeft() + nativeOffset);
+ Q_ASSERT(qMax(qAbs(diff.x()), qAbs(diff.y())) <= 1);
+ nativeRegion.translate(diff);
+ }
+ handle()->flush(window, nativeRegion, nativeOffset);
}
/*!
@@ -261,7 +230,8 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
void QBackingStore::resize(const QSize &size)
{
d_ptr->size = size;
- handle()->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents);
+ const qreal factor = d_ptr->deviceIndependentToNativeFactor();
+ handle()->resize(QHighDpi::scale(size, factor), QHighDpi::scale(d_ptr->staticContents, factor));
}
/*!
@@ -283,13 +253,13 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
// Disable scrolling for non-integer scroll deltas. For this case
// the existing rendered pixels can't be re-used, and we return
// false to signal that a repaint is needed.
- const qreal nativeDx = QHighDpi::toNativePixels(qreal(dx), d_ptr->window);
- const qreal nativeDy = QHighDpi::toNativePixels(qreal(dy), d_ptr->window);
+ const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
+ const qreal nativeDx = QHighDpi::scale(qreal(dx), toNativeFactor);
+ const qreal nativeDy = QHighDpi::scale(qreal(dy), toNativeFactor);
if (qFloor(nativeDx) != nativeDx || qFloor(nativeDy) != nativeDy)
return false;
- return handle()->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window),
- nativeDx, nativeDy);
+ return handle()->scroll(QHighDpi::scale(area, toNativeFactor), nativeDx, nativeDy);
}
/*!
@@ -297,6 +267,13 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
*/
void QBackingStore::setStaticContents(const QRegion &region)
{
+ [[maybe_unused]] static const bool didCheckPlatformSupport = []{
+ const auto *integration = QGuiApplicationPrivate::platformIntegration();
+ if (!integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents))
+ qWarning("QBackingStore::setStaticContents(): Platform does not support static contents");
+ return true;
+ }();
+
d_ptr->staticContents = region;
}
@@ -320,32 +297,34 @@ bool QBackingStore::hasStaticContents() const
void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
{
// make sure we don't detach
- uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits());
+ uchar *mem = const_cast<uchar*>(img.constBits());
qsizetype lineskip = img.bytesPerLine();
int depth = img.depth() >> 3;
const QRect imageRect(0, 0, img.width(), img.height());
- const QRect r = rect & imageRect & imageRect.translated(-offset);
- const QPoint p = rect.topLeft() + offset;
-
- if (r.isEmpty())
+ const QRect sourceRect = rect.intersected(imageRect).intersected(imageRect.translated(-offset));
+ if (sourceRect.isEmpty())
return;
+ const QRect destRect = sourceRect.translated(offset);
+ Q_ASSERT_X(imageRect.contains(destRect), "qt_scrollRectInImage",
+ "The sourceRect should already account for clipping, both pre and post scroll");
+
const uchar *src;
uchar *dest;
- if (r.top() < p.y()) {
- src = mem + r.bottom() * lineskip + r.left() * depth;
- dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth;
+ if (sourceRect.top() < destRect.top()) {
+ src = mem + sourceRect.bottom() * lineskip + sourceRect.left() * depth;
+ dest = mem + (destRect.top() + sourceRect.height() - 1) * lineskip + destRect.left() * depth;
lineskip = -lineskip;
} else {
- src = mem + r.top() * lineskip + r.left() * depth;
- dest = mem + p.y() * lineskip + p.x() * depth;
+ src = mem + sourceRect.top() * lineskip + sourceRect.left() * depth;
+ dest = mem + destRect.top() * lineskip + destRect.left() * depth;
}
- const int w = r.width();
- int h = r.height();
+ const int w = sourceRect.width();
+ int h = sourceRect.height();
const int bytes = w * depth;
// overlapping segments?
diff --git a/src/gui/painting/qbackingstore.h b/src/gui/painting/qbackingstore.h
index ed37e11a5b..3673d66a0f 100644
--- a/src/gui/painting/qbackingstore.h
+++ b/src/gui/painting/qbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBACKINGSTORE_H
#define QBACKINGSTORE_H
diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp
new file mode 100644
index 0000000000..c1452ca768
--- /dev/null
+++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp
@@ -0,0 +1,676 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qbackingstoredefaultcompositor_p.h"
+#include <QtGui/private/qwindow_p.h>
+#include <qpa/qplatformgraphicsbuffer.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QBackingStoreDefaultCompositor::~QBackingStoreDefaultCompositor()
+{
+ reset();
+}
+
+void QBackingStoreDefaultCompositor::reset()
+{
+ m_rhi = nullptr;
+ m_psNoBlend.reset();
+ m_psBlend.reset();
+ m_psPremulBlend.reset();
+ m_samplerNearest.reset();
+ m_samplerLinear.reset();
+ m_vbuf.reset();
+ m_texture.reset();
+ m_widgetQuadData.reset();
+ for (PerQuadData &d : m_textureQuadData)
+ d.reset();
+}
+
+QRhiTexture *QBackingStoreDefaultCompositor::toTexture(const QPlatformBackingStore *backingStore,
+ QRhi *rhi,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ QPlatformBackingStore::TextureFlags *flags) const
+{
+ return toTexture(backingStore->toImage(), rhi, resourceUpdates, dirtyRegion, flags);
+}
+
+QRhiTexture *QBackingStoreDefaultCompositor::toTexture(const QImage &sourceImage,
+ QRhi *rhi,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ QPlatformBackingStore::TextureFlags *flags) const
+{
+ Q_ASSERT(rhi);
+ Q_ASSERT(resourceUpdates);
+ Q_ASSERT(flags);
+
+ if (!m_rhi) {
+ m_rhi = rhi;
+ } else if (m_rhi != rhi) {
+ qWarning("QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
+ return nullptr;
+ }
+
+ QImage image = sourceImage;
+
+ bool needsConversion = false;
+ *flags = {};
+
+ switch (image.format()) {
+ case QImage::Format_ARGB32_Premultiplied:
+ *flags |= QPlatformBackingStore::TexturePremultiplied;
+ Q_FALLTHROUGH();
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ *flags |= QPlatformBackingStore::TextureSwizzle;
+ break;
+ case QImage::Format_RGBA8888_Premultiplied:
+ *flags |= QPlatformBackingStore::TexturePremultiplied;
+ Q_FALLTHROUGH();
+ case QImage::Format_RGBX8888:
+ case QImage::Format_RGBA8888:
+ break;
+ case QImage::Format_BGR30:
+ case QImage::Format_A2BGR30_Premultiplied:
+ // no fast path atm
+ needsConversion = true;
+ break;
+ case QImage::Format_RGB30:
+ case QImage::Format_A2RGB30_Premultiplied:
+ // no fast path atm
+ needsConversion = true;
+ break;
+ default:
+ needsConversion = true;
+ break;
+ }
+
+ if (image.size().isEmpty())
+ return nullptr;
+
+ const bool resized = !m_texture || m_texture->pixelSize() != image.size();
+ if (dirtyRegion.isEmpty() && !resized)
+ return m_texture.get();
+
+ if (needsConversion)
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+ else
+ image.detach(); // if it was just wrapping data, that's no good, we need ownership, so detach
+
+ if (resized) {
+ if (!m_texture)
+ m_texture.reset(rhi->newTexture(QRhiTexture::RGBA8, image.size()));
+ else
+ m_texture->setPixelSize(image.size());
+ m_texture->create();
+ resourceUpdates->uploadTexture(m_texture.get(), image);
+ } else {
+ QRect imageRect = image.rect();
+ QRect rect = dirtyRegion.boundingRect() & imageRect;
+ QRhiTextureSubresourceUploadDescription subresDesc(image);
+ subresDesc.setSourceTopLeft(rect.topLeft());
+ subresDesc.setSourceSize(rect.size());
+ subresDesc.setDestinationTopLeft(rect.topLeft());
+ QRhiTextureUploadDescription uploadDesc(QRhiTextureUploadEntry(0, 0, subresDesc));
+ resourceUpdates->uploadTexture(m_texture.get(), uploadDesc);
+ }
+
+ return m_texture.get();
+}
+
+static inline QRect scaledRect(const QRect &rect, qreal factor)
+{
+ return QRect(rect.topLeft() * factor, rect.size() * factor);
+}
+
+static inline QPoint scaledOffset(const QPoint &pt, qreal factor)
+{
+ return pt * factor;
+}
+
+static QRegion scaledRegion(const QRegion &region, qreal factor, const QPoint &offset)
+{
+ if (offset.isNull() && factor <= 1)
+ return region;
+
+ QVarLengthArray<QRect, 4> rects;
+ rects.reserve(region.rectCount());
+ for (const QRect &rect : region)
+ rects.append(scaledRect(rect.translated(offset), factor));
+
+ QRegion deviceRegion;
+ deviceRegion.setRects(rects.constData(), rects.size());
+ return deviceRegion;
+}
+
+static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport, bool invertY)
+{
+ qreal x_scale = target.width() / viewport.width();
+ qreal y_scale = target.height() / viewport.height();
+
+ const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft();
+ qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2);
+ qreal y_translate;
+ if (invertY)
+ y_translate = y_scale - 1 + ((relative_to_viewport.y() / viewport.height()) * 2);
+ else
+ y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2);
+
+ QMatrix4x4 matrix;
+ matrix(0,3) = x_translate;
+ matrix(1,3) = y_translate;
+
+ matrix(0,0) = x_scale;
+ matrix(1,1) = (invertY ? -1.0 : 1.0) * y_scale;
+
+ return matrix;
+}
+
+enum class SourceTransformOrigin {
+ BottomLeft,
+ TopLeft
+};
+
+static QMatrix3x3 sourceTransform(const QRectF &subTexture,
+ const QSize &textureSize,
+ SourceTransformOrigin origin)
+{
+ qreal x_scale = subTexture.width() / textureSize.width();
+ qreal y_scale = subTexture.height() / textureSize.height();
+
+ const QPointF topLeft = subTexture.topLeft();
+ qreal x_translate = topLeft.x() / textureSize.width();
+ qreal y_translate = topLeft.y() / textureSize.height();
+
+ if (origin == SourceTransformOrigin::TopLeft) {
+ y_scale = -y_scale;
+ y_translate = 1 - y_translate;
+ }
+
+ QMatrix3x3 matrix;
+ matrix(0,2) = x_translate;
+ matrix(1,2) = y_translate;
+
+ matrix(0,0) = x_scale;
+ matrix(1,1) = y_scale;
+
+ return matrix;
+}
+
+static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
+{
+ return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
+ topLeftRect.width(), topLeftRect.height());
+}
+
+static bool prepareDrawForRenderToTextureWidget(const QPlatformTextureList *textures,
+ int idx,
+ QWindow *window,
+ const QRect &deviceWindowRect,
+ const QPoint &offset,
+ bool invertTargetY,
+ bool invertSource,
+ QMatrix4x4 *target,
+ QMatrix3x3 *source)
+{
+ const QRect clipRect = textures->clipRect(idx);
+ if (clipRect.isEmpty())
+ return false;
+
+ QRect rectInWindow = textures->geometry(idx);
+ // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust
+ rectInWindow.translate(-offset);
+
+ const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
+ const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
+
+ *target = targetTransform(scaledRect(clippedRectInWindow, window->devicePixelRatio()),
+ deviceWindowRect,
+ invertTargetY);
+
+ *source = sourceTransform(scaledRect(srcRect, window->devicePixelRatio()),
+ scaledRect(rectInWindow, window->devicePixelRatio()).size(),
+ invertSource ? SourceTransformOrigin::TopLeft : SourceTransformOrigin::BottomLeft);
+
+ return true;
+}
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ qWarning("QBackingStoreDefaultCompositor: Could not find built-in shader %s "
+ "(is something wrong with QtGui library resources?)",
+ qPrintable(name));
+ return QShader();
+}
+
+static void updateMatrix3x3(QRhiResourceUpdateBatch *resourceUpdates, QRhiBuffer *ubuf, const QMatrix3x3 &m)
+{
+ // mat3 is still 4 floats per column in the uniform buffer (but there is no
+ // 4th column), so 48 bytes altogether, not 36 or 64.
+
+ float f[12];
+ const float *src = static_cast<const float *>(m.constData());
+ float *dst = f;
+ memcpy(dst, src, 3 * sizeof(float));
+ memcpy(dst + 4, src + 3, 3 * sizeof(float));
+ memcpy(dst + 8, src + 6, 3 * sizeof(float));
+
+ resourceUpdates->updateDynamicBuffer(ubuf, 64, 48, f);
+}
+
+enum class PipelineBlend {
+ None,
+ Alpha,
+ PremulAlpha
+};
+
+static QRhiGraphicsPipeline *createGraphicsPipeline(QRhi *rhi,
+ QRhiShaderResourceBindings *srb,
+ QRhiRenderPassDescriptor *rpDesc,
+ PipelineBlend blend)
+{
+ QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
+
+ switch (blend) {
+ case PipelineBlend::Alpha:
+ {
+ QRhiGraphicsPipeline::TargetBlend blend;
+ blend.enable = true;
+ blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
+ blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ blend.srcAlpha = QRhiGraphicsPipeline::One;
+ blend.dstAlpha = QRhiGraphicsPipeline::One;
+ ps->setTargetBlends({ blend });
+ }
+ break;
+ case PipelineBlend::PremulAlpha:
+ {
+ QRhiGraphicsPipeline::TargetBlend blend;
+ blend.enable = true;
+ blend.srcColor = QRhiGraphicsPipeline::One;
+ blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ blend.srcAlpha = QRhiGraphicsPipeline::One;
+ blend.dstAlpha = QRhiGraphicsPipeline::One;
+ ps->setTargetBlends({ blend });
+ }
+ break;
+ default:
+ break;
+ }
+
+ ps->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(":/qt-project.org/gui/painting/shaders/backingstorecompose.vert.qsb"_L1) },
+ { QRhiShaderStage::Fragment, getShader(":/qt-project.org/gui/painting/shaders/backingstorecompose.frag.qsb"_L1) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({ { 5 * sizeof(float) } });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, quint32(3 * sizeof(float)) }
+ });
+ ps->setVertexInputLayout(inputLayout);
+ ps->setShaderResourceBindings(srb);
+ ps->setRenderPassDescriptor(rpDesc);
+
+ if (!ps->create()) {
+ qWarning("QBackingStoreDefaultCompositor: Failed to build graphics pipeline");
+ delete ps;
+ return nullptr;
+ }
+ return ps;
+}
+
+static const int UBUF_SIZE = 120;
+
+QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra)
+{
+ PerQuadData d;
+
+ d.ubuf = m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE);
+ if (!d.ubuf->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create uniform buffer");
+
+ d.srb = m_rhi->newShaderResourceBindings();
+ d.srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_samplerNearest.get())
+ });
+ if (!d.srb->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create srb");
+ d.lastUsedTexture = texture;
+
+ if (textureExtra) {
+ d.srbExtra = m_rhi->newShaderResourceBindings();
+ d.srbExtra->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_samplerNearest.get())
+ });
+ if (!d.srbExtra->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create srb");
+ }
+
+ d.lastUsedTextureExtra = textureExtra;
+
+ return d;
+}
+
+void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra,
+ UpdateQuadDataOptions options)
+{
+ // This whole check-if-texture-ptr-is-different is needed because there is
+ // nothing saying a QPlatformTextureList cannot return a different
+ // QRhiTexture* from the same index in a subsequent flush.
+
+ const QRhiSampler::Filter filter = options.testFlag(NeedsLinearFiltering) ? QRhiSampler::Linear : QRhiSampler::Nearest;
+ if ((d->lastUsedTexture == texture && d->lastUsedFilter == filter) || !d->srb)
+ return;
+
+ QRhiSampler *sampler = filter == QRhiSampler::Linear ? m_samplerLinear.get() : m_samplerNearest.get();
+ d->srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler)
+ });
+
+ d->srb->updateResources(QRhiShaderResourceBindings::BindingsAreSorted);
+ d->lastUsedTexture = texture;
+ d->lastUsedFilter = filter;
+
+ if (textureExtra) {
+ d->srbExtra->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, sampler)
+ });
+
+ d->srbExtra->updateResources(QRhiShaderResourceBindings::BindingsAreSorted);
+ d->lastUsedTextureExtra = textureExtra;
+ }
+}
+
+void QBackingStoreDefaultCompositor::updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates,
+ const QMatrix4x4 &target, const QMatrix3x3 &source,
+ UpdateUniformOptions options)
+{
+ resourceUpdates->updateDynamicBuffer(d->ubuf, 0, 64, target.constData());
+ updateMatrix3x3(resourceUpdates, d->ubuf, source);
+ float opacity = 1.0f;
+ resourceUpdates->updateDynamicBuffer(d->ubuf, 112, 4, &opacity);
+ qint32 textureSwizzle = options;
+ resourceUpdates->updateDynamicBuffer(d->ubuf, 116, 4, &textureSwizzle);
+}
+
+void QBackingStoreDefaultCompositor::ensureResources(QRhiResourceUpdateBatch *resourceUpdates, QRhiRenderPassDescriptor *rpDesc)
+{
+ static const float vertexData[] = {
+ -1, -1, 0, 0, 0,
+ -1, 1, 0, 0, 1,
+ 1, -1, 0, 1, 0,
+ -1, 1, 0, 0, 1,
+ 1, -1, 0, 1, 0,
+ 1, 1, 0, 1, 1
+ };
+
+ if (!m_vbuf) {
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ if (m_vbuf->create())
+ resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
+ else
+ qWarning("QBackingStoreDefaultCompositor: Failed to create vertex buffer");
+ }
+
+ if (!m_samplerNearest) {
+ m_samplerNearest.reset(m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ if (!m_samplerNearest->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Nearest filtering)");
+ }
+
+ if (!m_samplerLinear) {
+ m_samplerLinear.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ if (!m_samplerLinear->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Linear filtering)");
+ }
+
+ if (!m_widgetQuadData.isValid())
+ m_widgetQuadData = createPerQuadData(m_texture.get());
+
+ QRhiShaderResourceBindings *srb = m_widgetQuadData.srb; // just for the layout
+ if (!m_psNoBlend)
+ m_psNoBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::None));
+ if (!m_psBlend)
+ m_psBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::Alpha));
+ if (!m_psPremulBlend)
+ m_psPremulBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::PremulAlpha));
+}
+
+QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatformBackingStore *backingStore,
+ QRhi *rhi,
+ QRhiSwapChain *swapchain,
+ QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground)
+{
+ if (!rhi)
+ return QPlatformBackingStore::FlushFailed;
+
+ Q_ASSERT(textures); // may be empty if there are no render-to-texture widgets at all, but null it cannot be
+
+ if (!m_rhi) {
+ m_rhi = rhi;
+ } else if (m_rhi != rhi) {
+ qWarning("QBackingStoreDefaultCompositor: the QRhi has changed unexpectedly, this should not happen");
+ return QPlatformBackingStore::FlushFailed;
+ }
+
+ if (!qt_window_private(window)->receivedExpose)
+ return QPlatformBackingStore::FlushSuccess;
+
+ qCDebug(lcQpaBackingStore) << "Composing and flushing" << region << "of" << window
+ << "at offset" << offset << "with" << textures->count() << "texture(s) in" << textures
+ << "via swapchain" << swapchain;
+
+ QWindowPrivate::get(window)->lastComposeTime.start();
+
+ if (swapchain->currentPixelSize() != swapchain->surfacePixelSize())
+ swapchain->createOrResize();
+
+ // Start recording a new frame.
+ QRhi::FrameOpResult frameResult = rhi->beginFrame(swapchain);
+ if (frameResult == QRhi::FrameOpSwapChainOutOfDate) {
+ if (!swapchain->createOrResize())
+ return QPlatformBackingStore::FlushFailed;
+ frameResult = rhi->beginFrame(swapchain);
+ }
+ if (frameResult == QRhi::FrameOpDeviceLost)
+ return QPlatformBackingStore::FlushFailedDueToLostDevice;
+ if (frameResult != QRhi::FrameOpSuccess)
+ return QPlatformBackingStore::FlushFailed;
+
+ // Prepare resource updates.
+ QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch();
+ QPlatformBackingStore::TextureFlags flags;
+
+ bool gotTextureFromGraphicsBuffer = false;
+ if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
+ if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
+ const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format());
+ const QSize size = graphicsBuffer->size();
+ QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format);
+ toTexture(wrapperImage, rhi, resourceUpdates, scaledRegion(region, sourceDevicePixelRatio, offset), &flags);
+ gotTextureFromGraphicsBuffer = true;
+ graphicsBuffer->unlock();
+ if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
+ flags |= QPlatformBackingStore::TextureFlip;
+ }
+ }
+ if (!gotTextureFromGraphicsBuffer)
+ toTexture(backingStore, rhi, resourceUpdates, scaledRegion(region, sourceDevicePixelRatio, offset), &flags);
+
+ ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
+
+ UpdateUniformOptions uniformOptions;
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ if (flags & QPlatformBackingStore::TextureSwizzle)
+ uniformOptions |= NeedsRedBlueSwap;
+#else
+ if (flags & QPlatformBackingStore::TextureSwizzle)
+ uniformOptions |= NeedsAlphaRotate;
+#endif
+ const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
+ SourceTransformOrigin origin = SourceTransformOrigin::TopLeft;
+ if (flags & QPlatformBackingStore::TextureFlip)
+ origin = SourceTransformOrigin::BottomLeft;
+
+ const qreal dpr = window->devicePixelRatio();
+ const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
+ const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
+ // If sourceWindowRect is larger than deviceWindowRect, we are doing high
+ // DPI downscaling. In that case Linear filtering is a must, whereas for the
+ // 1:1 case Nearest must be used for Qt 5 visual compatibility.
+ const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
+ && sourceWindowRect.height() > deviceWindowRect.height();
+
+ const bool invertTargetY = !rhi->isYUpInNDC();
+ const bool invertSource = !rhi->isYUpInFramebuffer();
+
+ if (m_texture) {
+ // The backingstore is for the entire tlw. In case of native children, offset tells the position
+ // relative to the tlw. The window rect is scaled by the source device pixel ratio to get
+ // the source rect.
+ const QPoint sourceWindowOffset = scaledOffset(offset, sourceDevicePixelRatio);
+ const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
+ const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
+ QMatrix4x4 target; // identity
+ if (invertTargetY)
+ target.data()[5] = -1.0f;
+ updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
+ if (needsLinearSampler)
+ updatePerQuadData(&m_widgetQuadData, m_texture.get(), nullptr, NeedsLinearFiltering);
+ }
+
+ const int textureWidgetCount = textures->count();
+ const int oldTextureQuadDataCount = m_textureQuadData.size();
+ if (oldTextureQuadDataCount != textureWidgetCount) {
+ for (int i = textureWidgetCount; i < oldTextureQuadDataCount; ++i)
+ m_textureQuadData[i].reset();
+ m_textureQuadData.resize(textureWidgetCount);
+ }
+
+ for (int i = 0; i < textureWidgetCount; ++i) {
+ const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
+ ? !invertSource : invertSource;
+ QMatrix4x4 target;
+ QMatrix3x3 source;
+ if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
+ offset, invertTargetY, invertSourceForTextureWidget,
+ &target, &source))
+ {
+ m_textureQuadData[i].reset();
+ continue;
+ }
+ QRhiTexture *t = textures->texture(i);
+ QRhiTexture *tExtra = textures->textureExtra(i);
+ if (t) {
+ if (!m_textureQuadData[i].isValid())
+ m_textureQuadData[i] = createPerQuadData(t, tExtra);
+ else
+ updatePerQuadData(&m_textureQuadData[i], t, tExtra);
+ updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
+ if (needsLinearSampler)
+ updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
+ } else {
+ m_textureQuadData[i].reset();
+ }
+ }
+
+ // Record the render pass (with committing the resource updates).
+ QRhiCommandBuffer *cb = swapchain->currentFrameCommandBuffer();
+ const QSize outputSizeInPixels = swapchain->currentPixelSize();
+ QColor clearColor = translucentBackground ? Qt::transparent : Qt::black;
+
+ cb->resourceUpdate(resourceUpdates);
+
+ auto render = [&](std::optional<QRhiSwapChain::StereoTargetBuffer> buffer = std::nullopt) {
+ QRhiRenderTarget* target = nullptr;
+ if (buffer.has_value())
+ target = swapchain->currentFrameRenderTarget(buffer.value());
+ else
+ target = swapchain->currentFrameRenderTarget();
+
+ cb->beginPass(target, clearColor, { 1.0f, 0 });
+
+ cb->setGraphicsPipeline(m_psNoBlend.get());
+ cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
+ QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+
+ // Textures for renderToTexture widgets.
+ for (int i = 0; i < textureWidgetCount; ++i) {
+ if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
+ if (m_textureQuadData[i].isValid()) {
+
+ QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
+ if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
+ srb = m_textureQuadData[i].srbExtra;
+
+ cb->setShaderResources(srb);
+ cb->draw(6);
+ }
+ }
+ }
+
+ cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
+
+ // Backingstore texture with the normal widgets.
+ if (m_texture) {
+ cb->setShaderResources(m_widgetQuadData.srb);
+ cb->draw(6);
+ }
+
+ // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
+ for (int i = 0; i < textureWidgetCount; ++i) {
+ const QPlatformTextureList::Flags flags = textures->flags(i);
+ if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
+ if (m_textureQuadData[i].isValid()) {
+ if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
+ cb->setGraphicsPipeline(m_psPremulBlend.get());
+ else
+ cb->setGraphicsPipeline(m_psBlend.get());
+
+ QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
+ if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
+ srb = m_textureQuadData[i].srbExtra;
+
+ cb->setShaderResources(srb);
+ cb->draw(6);
+ }
+ }
+ }
+
+ cb->endPass();
+ };
+
+ if (swapchain->window()->format().stereo()) {
+ render(QRhiSwapChain::LeftBuffer);
+ render(QRhiSwapChain::RightBuffer);
+ } else
+ render();
+
+ rhi->endFrame(swapchain);
+
+ return QPlatformBackingStore::FlushSuccess;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qbackingstoredefaultcompositor_p.h b/src/gui/painting/qbackingstoredefaultcompositor_p.h
new file mode 100644
index 0000000000..c5a8ffd328
--- /dev/null
+++ b/src/gui/painting/qbackingstoredefaultcompositor_p.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QBACKINGSTOREDEFAULTCOMPOSITOR_P_H
+#define QBACKINGSTOREDEFAULTCOMPOSITOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qpa/qplatformbackingstore.h>
+#include <rhi/qrhi.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBackingStoreDefaultCompositor
+{
+public:
+ ~QBackingStoreDefaultCompositor();
+
+ void reset();
+
+ QRhiTexture *toTexture(const QPlatformBackingStore *backingStore,
+ QRhi *rhi,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ QPlatformBackingStore::TextureFlags *flags) const;
+
+ QPlatformBackingStore::FlushResult flush(QPlatformBackingStore *backingStore,
+ QRhi *rhi,
+ QRhiSwapChain *swapchain,
+ QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground);
+
+private:
+ enum UpdateUniformOption {
+ NeedsRedBlueSwap = 1 << 0,
+ NeedsAlphaRotate = 1 << 1
+ };
+ Q_DECLARE_FLAGS(UpdateUniformOptions, UpdateUniformOption)
+ enum UpdateQuadDataOption {
+ NeedsLinearFiltering = 1 << 0
+ };
+ Q_DECLARE_FLAGS(UpdateQuadDataOptions, UpdateQuadDataOption)
+
+ void ensureResources(QRhiResourceUpdateBatch *resourceUpdates, QRhiRenderPassDescriptor *rpDesc);
+ QRhiTexture *toTexture(const QImage &image,
+ QRhi *rhi,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ QPlatformBackingStore::TextureFlags *flags) const;
+
+ mutable QRhi *m_rhi = nullptr;
+ mutable std::unique_ptr<QRhiTexture> m_texture;
+
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ std::unique_ptr<QRhiSampler> m_samplerNearest;
+ std::unique_ptr<QRhiSampler> m_samplerLinear;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psNoBlend;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psBlend;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psPremulBlend;
+
+ struct PerQuadData {
+ QRhiBuffer *ubuf = nullptr;
+ // All srbs are layout-compatible.
+ QRhiShaderResourceBindings *srb = nullptr;
+ QRhiShaderResourceBindings *srbExtra = nullptr; // may be null (used for stereo)
+ QRhiTexture *lastUsedTexture = nullptr;
+ QRhiTexture *lastUsedTextureExtra = nullptr; // may be null (used for stereo)
+ QRhiSampler::Filter lastUsedFilter = QRhiSampler::None;
+ bool isValid() const { return ubuf && srb; }
+ void reset() {
+ delete ubuf;
+ ubuf = nullptr;
+ delete srb;
+ srb = nullptr;
+ if (srbExtra) {
+ delete srbExtra;
+ srbExtra = nullptr;
+ }
+ lastUsedTexture = nullptr;
+ lastUsedTextureExtra = nullptr;
+ lastUsedFilter = QRhiSampler::None;
+ }
+ };
+ PerQuadData m_widgetQuadData;
+ QVarLengthArray<PerQuadData, 8> m_textureQuadData;
+
+ PerQuadData createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra = nullptr);
+ void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr,
+ UpdateQuadDataOptions options = {});
+ void updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates,
+ const QMatrix4x4 &target, const QMatrix3x3 &source,
+ UpdateUniformOptions options = {});
+};
+
+QT_END_NAMESPACE
+
+#endif // QBACKINGSTOREDEFAULTCOMPOSITOR_P_H
diff --git a/src/gui/painting/qbackingstorerhisupport.cpp b/src/gui/painting/qbackingstorerhisupport.cpp
new file mode 100644
index 0000000000..fe5589dc2d
--- /dev/null
+++ b/src/gui/painting/qbackingstorerhisupport.cpp
@@ -0,0 +1,327 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qbackingstorerhisupport_p.h"
+#include <qpa/qplatformintegration.h>
+#include <private/qguiapplication_p.h>
+
+#if QT_CONFIG(opengl)
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#endif
+
+#if QT_CONFIG(vulkan)
+#include <QtGui/private/qvulkandefaultinstance_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore)
+
+QBackingStoreRhiSupport::~QBackingStoreRhiSupport()
+{
+ reset();
+}
+
+void QBackingStoreRhiSupport::SwapchainData::reset()
+{
+ delete swapchain;
+ delete renderPassDescriptor;
+ delete windowWatcher;
+ *this = {};
+}
+
+void QBackingStoreRhiSupport::reset()
+{
+ for (SwapchainData &d : m_swapchains)
+ d.reset();
+
+ m_swapchains.clear();
+
+ delete m_rhi;
+ m_rhi = nullptr;
+
+ delete m_openGLFallbackSurface;
+ m_openGLFallbackSurface = nullptr;
+}
+
+bool QBackingStoreRhiSupport::create()
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering))
+ return false;
+
+ // note: m_window may be null (special case for fully offscreen rendering)
+
+ QRhi *rhi = nullptr;
+ QOffscreenSurface *surface = nullptr;
+ QRhi::Flags flags;
+
+ // These must be the same env.vars Qt Quick uses (as documented), in order
+ // to ensure symmetry in the behavior between a QQuickWindow and a
+ // (QRhi-based) widget top-level window.
+ if (qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"))
+ flags |= QRhi::PreferSoftwareRenderer;
+ if (qEnvironmentVariableIntValue("QSG_RHI_PROFILE"))
+ flags |= QRhi::EnableDebugMarkers | QRhi::EnableTimestamps;
+
+ if (m_config.api() == QPlatformBackingStoreRhiConfig::Null) {
+ QRhiNullInitParams params;
+ rhi = QRhi::create(QRhi::Null, &params, flags);
+ }
+
+#if QT_CONFIG(opengl)
+ if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::OpenGL) {
+ surface = QRhiGles2InitParams::newFallbackSurface(m_format);
+ QRhiGles2InitParams params;
+ params.fallbackSurface = surface;
+ params.window = m_window;
+ params.format = m_format;
+ params.shareContext = qt_gl_global_share_context();
+ rhi = QRhi::create(QRhi::OpenGLES2, &params, flags);
+ }
+#endif
+
+#ifdef Q_OS_WIN
+ if (!rhi) {
+ if (m_config.api() == QPlatformBackingStoreRhiConfig::D3D11) {
+ QRhiD3D11InitParams params;
+ params.enableDebugLayer = m_config.isDebugLayerEnabled();
+ rhi = QRhi::create(QRhi::D3D11, &params, flags);
+ if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ qCDebug(lcQpaBackingStore, "Failed to create a D3D11 device with default settings; "
+ "attempting to get a software rasterizer backed device instead");
+ flags |= QRhi::PreferSoftwareRenderer;
+ rhi = QRhi::create(QRhi::D3D11, &params, flags);
+ }
+ } else if (m_config.api() == QPlatformBackingStoreRhiConfig::D3D12) {
+ QRhiD3D12InitParams params;
+ params.enableDebugLayer = m_config.isDebugLayerEnabled();
+ rhi = QRhi::create(QRhi::D3D12, &params, flags);
+ if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ qCDebug(lcQpaBackingStore, "Failed to create a D3D12 device with default settings; "
+ "attempting to get a software rasterizer backed device instead");
+ flags |= QRhi::PreferSoftwareRenderer;
+ rhi = QRhi::create(QRhi::D3D12, &params, flags);
+ }
+ }
+ }
+#endif
+
+#if QT_CONFIG(metal)
+ if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Metal) {
+ QRhiMetalInitParams params;
+ // For parity with Qt Quick, fall back to OpenGL when there is no Metal (f.ex. in macOS virtual machines).
+ if (QRhi::probe(QRhi::Metal, &params)) {
+ rhi = QRhi::create(QRhi::Metal, &params, flags);
+ } else {
+ qCDebug(lcQpaBackingStore, "Metal does not seem to be supported. Falling back to OpenGL.");
+ rhi = QRhi::create(QRhi::OpenGLES2, &params, flags);
+ }
+ }
+#endif
+
+#if QT_CONFIG(vulkan)
+ if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan) {
+ if (m_config.isDebugLayerEnabled())
+ QVulkanDefaultInstance::setFlag(QVulkanDefaultInstance::EnableValidation);
+ QRhiVulkanInitParams params;
+ if (m_window) {
+ if (!m_window->vulkanInstance())
+ m_window->setVulkanInstance(QVulkanDefaultInstance::instance());
+ params.inst = m_window->vulkanInstance();
+ } else {
+ params.inst = QVulkanDefaultInstance::instance();
+ }
+ if (!params.inst) {
+ qWarning("No QVulkanInstance set for the top-level window, this is wrong.");
+ return false;
+ }
+ params.window = m_window;
+ rhi = QRhi::create(QRhi::Vulkan, &params, flags);
+ }
+#endif
+
+ if (!rhi) {
+ qWarning("Failed to create QRhi for QBackingStoreRhiSupport");
+ delete surface;
+ return false;
+ }
+
+ m_rhi = rhi;
+ m_openGLFallbackSurface = surface;
+ return true;
+}
+
+QRhiSwapChain *QBackingStoreRhiSupport::swapChainForWindow(QWindow *window)
+{
+ auto it = m_swapchains.constFind(window);
+ if (it != m_swapchains.constEnd())
+ return it.value().swapchain;
+
+ QRhiSwapChain *swapchain = nullptr;
+ QRhiRenderPassDescriptor *rp = nullptr;
+ if (window && m_rhi) {
+ QRhiSwapChain::Flags flags;
+ const QSurfaceFormat format = window->requestedFormat();
+ if (format.swapInterval() == 0)
+ flags |= QRhiSwapChain::NoVSync;
+ if (format.alphaBufferSize() > 0)
+ flags |= QRhiSwapChain::SurfaceHasNonPreMulAlpha;
+#if QT_CONFIG(vulkan)
+ if (m_config.api() == QPlatformBackingStoreRhiConfig::Vulkan && !window->vulkanInstance())
+ window->setVulkanInstance(QVulkanDefaultInstance::instance());
+#endif
+ qCDebug(lcQpaBackingStore) << "Creating swapchain for window" << window;
+ swapchain = m_rhi->newSwapChain();
+ swapchain->setWindow(window);
+ swapchain->setFlags(flags);
+ rp = swapchain->newCompatibleRenderPassDescriptor();
+ swapchain->setRenderPassDescriptor(rp);
+ if (!swapchain->createOrResize()) {
+ qWarning("Failed to create swapchain for window flushed with an RHI-enabled backingstore");
+ delete rp;
+ return nullptr;
+ }
+ }
+ if (swapchain) {
+ SwapchainData d;
+ d.swapchain = swapchain;
+ d.renderPassDescriptor = rp;
+ d.windowWatcher = new QBackingStoreRhiSupportWindowWatcher(this);
+ m_swapchains.insert(window, d);
+ window->installEventFilter(d.windowWatcher);
+ }
+ return swapchain;
+}
+
+bool QBackingStoreRhiSupportWindowWatcher::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::WindowAboutToChangeInternal
+ || (event->type() == QEvent::PlatformSurface
+ && static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed))
+ {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ auto it = m_rhiSupport->m_swapchains.find(window);
+ if (it != m_rhiSupport->m_swapchains.end()) {
+ qCDebug(lcQpaBackingStore) << event << "received for" << window << "- cleaning up swapchain";
+ auto data = *it;
+ m_rhiSupport->m_swapchains.erase(it);
+ data.reset(); // deletes 'this'
+ }
+ }
+ return false;
+}
+
+QSurface::SurfaceType QBackingStoreRhiSupport::surfaceTypeForConfig(const QPlatformBackingStoreRhiConfig &config)
+{
+ QSurface::SurfaceType type = QSurface::RasterSurface;
+ switch (config.api()) {
+ case QPlatformBackingStoreRhiConfig::D3D11:
+ case QPlatformBackingStoreRhiConfig::D3D12:
+ type = QSurface::Direct3DSurface;
+ break;
+ case QPlatformBackingStoreRhiConfig::Vulkan:
+ type = QSurface::VulkanSurface;
+ break;
+ case QPlatformBackingStoreRhiConfig::Metal:
+ type = QSurface::MetalSurface;
+ break;
+ case QPlatformBackingStoreRhiConfig::OpenGL:
+ type = QSurface::OpenGLSurface;
+ break;
+ default:
+ break;
+ }
+ return type;
+}
+
+QRhi::Implementation QBackingStoreRhiSupport::apiToRhiBackend(QPlatformBackingStoreRhiConfig::Api api)
+{
+ switch (api) {
+ case QPlatformBackingStoreRhiConfig::OpenGL:
+ return QRhi::OpenGLES2;
+ case QPlatformBackingStoreRhiConfig::Metal:
+ return QRhi::Metal;
+ case QPlatformBackingStoreRhiConfig::Vulkan:
+ return QRhi::Vulkan;
+ case QPlatformBackingStoreRhiConfig::D3D11:
+ return QRhi::D3D11;
+ case QPlatformBackingStoreRhiConfig::D3D12:
+ return QRhi::D3D12;
+ case QPlatformBackingStoreRhiConfig::Null:
+ return QRhi::Null;
+ default:
+ break;
+ }
+ return QRhi::Null;
+}
+
+bool QBackingStoreRhiSupport::checkForceRhi(QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType)
+{
+ static QPlatformBackingStoreRhiConfig config;
+ static bool checked = false;
+
+ if (!checked) {
+ checked = true;
+
+ const bool alwaysRhi = qEnvironmentVariableIntValue("QT_WIDGETS_RHI");
+ if (alwaysRhi)
+ config.setEnabled(true);
+
+ // if enabled, choose an api
+ if (config.isEnabled()) {
+#if defined(Q_OS_WIN)
+ config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
+#elif QT_CONFIG(metal)
+ config.setApi(QPlatformBackingStoreRhiConfig::Metal);
+#elif QT_CONFIG(opengl)
+ config.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
+#elif QT_CONFIG(vulkan)
+ config.setApi(QPlatformBackingStoreRhiConfig::Vulkan);
+#else
+ qWarning("QT_WIDGETS_RHI is set but no backend is available; ignoring");
+ return false;
+#endif
+
+ // the env.var. will always override
+ if (qEnvironmentVariableIsSet("QT_WIDGETS_RHI_BACKEND")) {
+ const QString backend = qEnvironmentVariable("QT_WIDGETS_RHI_BACKEND");
+#ifdef Q_OS_WIN
+ if (backend == QStringLiteral("d3d11") || backend == QStringLiteral("d3d"))
+ config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
+ if (backend == QStringLiteral("d3d12"))
+ config.setApi(QPlatformBackingStoreRhiConfig::D3D12);
+#endif
+#if QT_CONFIG(metal)
+ if (backend == QStringLiteral("metal"))
+ config.setApi(QPlatformBackingStoreRhiConfig::Metal);
+#endif
+#if QT_CONFIG(opengl)
+ if (backend == QStringLiteral("opengl") || backend == QStringLiteral("gl"))
+ config.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
+#endif
+#if QT_CONFIG(vulkan)
+ if (backend == QStringLiteral("vulkan"))
+ config.setApi(QPlatformBackingStoreRhiConfig::Vulkan);
+#endif
+ }
+
+ if (qEnvironmentVariableIntValue("QT_WIDGETS_RHI_DEBUG_LAYER"))
+ config.setDebugLayer(true);
+ }
+
+ qCDebug(lcQpaBackingStore) << "Check for forced use of QRhi resulted in enable"
+ << config.isEnabled() << "with api" << QRhi::backendName(apiToRhiBackend(config.api()));
+ }
+
+ if (config.isEnabled()) {
+ if (outConfig)
+ *outConfig = config;
+ if (outType)
+ *outType = surfaceTypeForConfig(config);
+ return true;
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qbackingstorerhisupport_p.h b/src/gui/painting/qbackingstorerhisupport_p.h
new file mode 100644
index 0000000000..39ce36c680
--- /dev/null
+++ b/src/gui/painting/qbackingstorerhisupport_p.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QBACKINGSTORERHISUPPORT_P_H
+#define QBACKINGSTORERHISUPPORT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtGui/qoffscreensurface.h>
+#include <rhi/qrhi.h>
+#include <qpa/qplatformbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QBackingStoreRhiSupport
+{
+public:
+ ~QBackingStoreRhiSupport();
+
+ void reset();
+
+ void setFormat(const QSurfaceFormat &format) { m_format = format; }
+ void setWindow(QWindow *window) { m_window = window; }
+ void setConfig(const QPlatformBackingStoreRhiConfig &config) { m_config = config; }
+
+ bool create();
+
+ QRhiSwapChain *swapChainForWindow(QWindow *window);
+
+ static QSurface::SurfaceType surfaceTypeForConfig(const QPlatformBackingStoreRhiConfig &config);
+
+ static bool checkForceRhi(QPlatformBackingStoreRhiConfig *outConfig, QSurface::SurfaceType *outType);
+
+ static QRhi::Implementation apiToRhiBackend(QPlatformBackingStoreRhiConfig::Api api);
+
+ QRhi *rhi() const { return m_rhi; }
+
+private:
+ QSurfaceFormat m_format;
+ QWindow *m_window = nullptr;
+ QPlatformBackingStoreRhiConfig m_config;
+ QRhi *m_rhi = nullptr;
+ QOffscreenSurface *m_openGLFallbackSurface = nullptr;
+ struct SwapchainData {
+ QRhiSwapChain *swapchain = nullptr;
+ QRhiRenderPassDescriptor *renderPassDescriptor = nullptr;
+ QObject *windowWatcher = nullptr;
+ void reset();
+ };
+ QHash<QWindow *, SwapchainData> m_swapchains;
+ friend class QBackingStoreRhiSupportWindowWatcher;
+};
+
+class QBackingStoreRhiSupportWindowWatcher : public QObject
+{
+public:
+ QBackingStoreRhiSupportWindowWatcher(QBackingStoreRhiSupport *rhiSupport) : m_rhiSupport(rhiSupport) { }
+ bool eventFilter(QObject *obj, QEvent *ev) override;
+private:
+ QBackingStoreRhiSupport *m_rhiSupport;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBACKINGSTORERHISUPPORT_P_H
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index 7622262da9..5b2a962661 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -1,49 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbezier_p.h"
#include <qdebug.h>
#include <qline.h>
-#include <qpolygon.h>
-#include <qvector.h>
-#include <qlist.h>
#include <qmath.h>
+#include <qpolygon.h>
#include <private/qnumeric_p.h>
@@ -219,15 +181,17 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse
const qreal o2 = offset*offset;
const qreal max_dist_line = threshold*offset*offset;
const qreal max_dist_normal = threshold*offset;
- const qreal spacing = qreal(0.25);
- for (qreal i = spacing; i < qreal(0.99); i += spacing) {
- QPointF p1 = b1->pointAt(i);
- QPointF p2 = b2->pointAt(i);
+ const int divisions = 4;
+ const qreal spacing = qreal(1.0) / divisions;
+ qreal t = spacing;
+ for (int i = 1; i < divisions; ++i, t += spacing) {
+ QPointF p1 = b1->pointAt(t);
+ QPointF p2 = b2->pointAt(t);
qreal d = (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y());
if (qAbs(d - o2) > max_dist_line)
return Split;
- QPointF normalPoint = b1->normalVector(i);
+ QPointF normalPoint = b1->normalVector(t);
qreal l = qAbs(normalPoint.x()) + qAbs(normalPoint.y());
if (l != qreal(0.0)) {
d = qAbs( normalPoint.x()*(p1.y() - p2.y()) - normalPoint.y()*(p1.x() - p2.x()) ) / l;
@@ -238,6 +202,8 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse
return Ok;
}
+QT_WARNING_DISABLE_FLOAT_COMPARE
+
static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
{
int map[4];
@@ -285,6 +251,8 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr
QPointF points_shifted[4];
QLineF prev = QLineF(QPointF(), points[1] - points[0]);
+ if (!prev.length())
+ return Discard;
QPointF prev_normal = prev.normalVector().unitVector().p2();
points_shifted[0] = points[0] + offset * prev_normal;
@@ -471,7 +439,7 @@ void QBezier::addIfClose(qreal *length, qreal error) const
chord = QLineF(QPointF(x1, y1),QPointF(x4, y4)).length();
- if((len-chord) > error) {
+ if ((len-chord) > error) {
const auto halves = split(); /* split in two */
halves.first.addIfClose(length, error); /* try left side */
halves.second.addIfClose(length, error); /* try right side */
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h
index bf712822a2..6c39dd55f9 100644
--- a/src/gui/painting/qbezier_p.h
+++ b/src/gui/painting/qbezier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBEZIER_P_H
#define QBEZIER_P_H
@@ -54,7 +18,6 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qline.h"
#include "QtCore/qlist.h"
-#include "QtCore/qpair.h"
#include "QtCore/qpoint.h"
#include "QtCore/qrect.h"
#include "QtGui/qtransform.h"
diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp
index 348eceb47f..fa9f89262c 100644
--- a/src/gui/painting/qblendfunctions.cpp
+++ b/src/gui/painting/qblendfunctions.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qmath.h>
#include "qblendfunctions_p.h"
@@ -96,7 +60,7 @@ struct Blend_ARGB32_on_RGB16_SourceAlpha {
const quint8 alpha = qAlpha(src);
if (alpha) {
quint16 s = qConvertRgb32To16(src);
- if(alpha < 255)
+ if (alpha < 255)
s += BYTE_MUL_RGB16(*dst, 255 - alpha);
*dst = s;
}
@@ -113,9 +77,9 @@ struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha {
inline void write(quint16 *dst, quint32 src) {
src = BYTE_MUL(src, m_alpha);
const quint8 alpha = qAlpha(src);
- if(alpha) {
+ if (alpha) {
quint16 s = qConvertRgb32To16(src);
- if(alpha < 255)
+ if (alpha < 255)
s += BYTE_MUL_RGB16(*dst, 255 - alpha);
*dst = s;
}
@@ -188,7 +152,7 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
if (const_alpha == 256) {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(dst, src, length);
dst += dbpl;
src += sbpl;
@@ -198,7 +162,7 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
const quint16 *s = (const quint16 *) src;
quint8 a = (255 * const_alpha) >> 8;
quint8 ia = 255 - a;
- while (h--) {
+ while (--h >= 0) {
for (int x=0; x<w; ++x) {
d[x] = BYTE_MUL_RGB16(s[x], a) + BYTE_MUL_RGB16(d[x], ia);
}
diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h
index 080da98ec4..2f5ed36c73 100644
--- a/src/gui/painting/qblendfunctions_p.h
+++ b/src/gui/painting/qblendfunctions_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLENDFUNCTIONS_P_H
#define QBLENDFUNCTIONS_P_H
@@ -125,7 +89,7 @@ void qt_scale_image_16bit(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(SRC)))
--w;
- while (h--) {
+ while (--h >= 0) {
const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
quint32 srcx = basex;
int x = 0;
@@ -216,7 +180,7 @@ template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(quint32)))
--w;
- while (h--) {
+ while (--h >= 0) {
const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
quint32 srcx = basex;
int x = 0;
@@ -246,25 +210,32 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
Blender blender)
{
- int fromY = qMax(qRound(topY), clip.top());
- int toY = qMin(qRound(bottomY), clip.top() + clip.height());
+ qint64 fromY = qMax(qRound(topY), clip.top());
+ qint64 toY = qMin(qRound(bottomY), clip.top() + clip.height());
if (fromY >= toY)
return;
qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y);
qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y);
- int dx_l = int(leftSlope * 0x10000);
- int dx_r = int(rightSlope * 0x10000);
- int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
- int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
-
- int fromX, toX, x1, x2, u, v, i, ii;
+ qint64 dx_l = qint64(leftSlope * 0x10000);
+ qint64 dx_r = qint64(rightSlope * 0x10000);
+ qint64 x_l = qint64((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000);
+ qint64 x_r = qint64((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000);
+
+ qint64 sourceRectTop = qint64(sourceRect.top());
+ qint64 sourceRectLeft = qint64(sourceRect.left());
+ qint64 sourceRectWidth = qint64(sourceRect.width());
+ qint64 sourceRectHeight = qint64(sourceRect.height());
+ qint64 clipLeft = qint64(clip.left());
+ qint64 clipWidth = qint64(clip.width());
+
+ qint64 fromX, toX, x1, x2, u, v, i, ii;
DestT *line;
- for (int y = fromY; y < toY; ++y) {
+ for (qint64 y = fromY; y < toY; ++y) {
line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
- fromX = qMax(x_l >> 16, clip.left());
- toX = qMin(x_r >> 16, clip.left() + clip.width());
+ fromX = qMax(x_l >> 16, clipLeft);
+ toX = qMin(x_r >> 16, clipLeft + clipWidth);
if (fromX < toX) {
// Because of rounding, we can get source coordinates outside the source image.
// Clamp these coordinates to the source rect to avoid segmentation fault and
@@ -275,10 +246,10 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
u = x1 * dudx + y * dudy + u0;
v = x1 * dvdx + y * dvdy + v0;
for (; x1 < toX; ++x1) {
- int uu = u >> 16;
- int vv = v >> 16;
- if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
- && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
+ qint64 uu = u >> 16;
+ qint64 vv = v >> 16;
+ if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth
+ && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) {
break;
}
u += dudx;
@@ -290,10 +261,10 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
u = (x2 - 1) * dudx + y * dudy + u0;
v = (x2 - 1) * dvdx + y * dvdy + v0;
for (; x2 > x1; --x2) {
- int uu = u >> 16;
- int vv = v >> 16;
- if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
- && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
+ qint64 uu = u >> 16;
+ qint64 vv = v >> 16;
+ if (uu >= sourceRectLeft && uu < sourceRectLeft + sourceRectWidth
+ && vv >= sourceRectTop && vv < sourceRectTop + sourceRectHeight) {
break;
}
u -= dudx;
@@ -308,8 +279,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
// Beginning of the scan line, with per-pixel checks.
i = x1 - fromX;
while (i) {
- int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
- int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
+ qint64 uu = qBound(sourceRectLeft, u >> 16, sourceRectLeft + sourceRectWidth - 1);
+ qint64 vv = qBound(sourceRectTop, v >> 16, sourceRectTop + sourceRectHeight - 1);
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
u += dudx;
v += dvdx;
@@ -348,8 +319,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
// End of the scan line, with per-pixel checks.
i = toX - x2;
while (i) {
- int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
- int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
+ qint64 uu = qBound(sourceRectLeft, u >> 16, sourceRectLeft + sourceRectWidth - 1);
+ qint64 vv = qBound(sourceRectTop, v >> 16, sourceRectTop + sourceRectHeight - 1);
blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
u += dudx;
v += dvdx;
diff --git a/src/gui/painting/qblittable.cpp b/src/gui/painting/qblittable.cpp
index 494104251f..75141537a9 100644
--- a/src/gui/painting/qblittable.cpp
+++ b/src/gui/painting/qblittable.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qblittable_p.h"
diff --git a/src/gui/painting/qblittable_p.h b/src/gui/painting/qblittable_p.h
index 24440c3c61..55c66e1535 100644
--- a/src/gui/painting/qblittable_p.h
+++ b/src/gui/painting/qblittable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBLITTABLE_P_H
#define QBLITTABLE_P_H
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index 172d51a487..b053896233 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qbrush.h"
#include "qpixmap.h"
@@ -54,9 +18,17 @@
#include <QtCore/qnumeric.h>
#include <QtCore/qfile.h>
#include <QtCore/qmutex.h>
+#include <QtCore/private/qoffsetstringarray_p.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+// Avoid an ABI break due to the QScopedPointer->std::unique_ptr change
+static_assert(sizeof(QBrush::DataPtr) == sizeof(QScopedPointer<QBrushData, QBrushDataPointerDeleter>));
+#endif
+
const uchar *qt_patternForBrush(int brushStyle, bool invert)
{
Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
@@ -109,7 +81,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
{
QPixmap pm;
- QString key = QLatin1String("$qt-brush$")
+ QString key = "$qt-brush$"_L1
% HexString<uint>(brushStyle)
% QLatin1Char(invert ? '1' : '0');
if (!QPixmapCache::find(key, &pm)) {
@@ -231,7 +203,7 @@ bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush)
{
if (brush.style() != Qt::TexturePattern)
return false;
- QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data());
+ QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.get());
return tx_data->m_has_pixmap_texture;
}
@@ -240,31 +212,27 @@ struct QGradientBrushData : public QBrushData
QGradient gradient;
};
-struct QBrushDataPointerDeleter
+static void deleteData(QBrushData *d)
{
- static inline void deleteData(QBrushData *d)
- {
- switch (d->style) {
- case Qt::TexturePattern:
- delete static_cast<QTexturedBrushData*>(d);
- break;
- case Qt::LinearGradientPattern:
- case Qt::RadialGradientPattern:
- case Qt::ConicalGradientPattern:
- delete static_cast<QGradientBrushData*>(d);
- break;
- default:
- delete d;
- }
+ switch (d->style) {
+ case Qt::TexturePattern:
+ delete static_cast<QTexturedBrushData*>(d);
+ break;
+ case Qt::LinearGradientPattern:
+ case Qt::RadialGradientPattern:
+ case Qt::ConicalGradientPattern:
+ delete static_cast<QGradientBrushData*>(d);
+ break;
+ default:
+ delete d;
}
+}
- static inline void cleanup(QBrushData *d)
- {
- if (d && !d->ref.deref()) {
- deleteData(d);
- }
- }
-};
+void QBrushDataPointerDeleter::operator()(QBrushData *d) const noexcept
+{
+ if (d && !d->ref.deref())
+ deleteData(d);
+}
/*!
\class QBrush
@@ -532,7 +500,7 @@ QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap)
*/
QBrush::QBrush(const QBrush &other)
- : d(other.d.data())
+ : d(other.d.get())
{
d->ref.ref();
}
@@ -559,7 +527,7 @@ QBrush::QBrush(const QGradient &gradient)
};
init(QColor(), enum_table[gradient.type()]);
- QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.data());
+ QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.get());
grad->gradient = gradient;
}
@@ -571,12 +539,7 @@ QBrush::~QBrush()
{
}
-void QBrush::cleanUp(QBrushData *x)
-{
- QBrushDataPointerDeleter::deleteData(x);
-}
-
-static Q_DECL_CONSTEXPR inline bool use_same_brushdata(Qt::BrushStyle lhs, Qt::BrushStyle rhs)
+static constexpr inline bool use_same_brushdata(Qt::BrushStyle lhs, Qt::BrushStyle rhs)
{
return lhs == rhs // includes Qt::TexturePattern
|| (lhs >= Qt::NoBrush && lhs <= Qt::DiagCrossPattern && rhs >= Qt::NoBrush && rhs <= Qt::DiagCrossPattern)
@@ -591,12 +554,12 @@ void QBrush::detach(Qt::BrushStyle newStyle)
return;
}
- QScopedPointer<QBrushData, QBrushDataPointerDeleter> x;
+ DataPtr x;
switch(newStyle) {
case Qt::TexturePattern: {
QTexturedBrushData *tbd = new QTexturedBrushData;
if (d->style == Qt::TexturePattern) {
- QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
+ QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
if (data->m_has_pixmap_texture)
tbd->setPixmap(data->pixmap());
else
@@ -614,7 +577,7 @@ void QBrush::detach(Qt::BrushStyle newStyle)
case Qt::RadialGradientPattern:
case Qt::ConicalGradientPattern:
gbd->gradient =
- static_cast<QGradientBrushData *>(d.data())->gradient;
+ static_cast<QGradientBrushData *>(d.get())->gradient;
break;
default:
break;
@@ -647,7 +610,7 @@ QBrush &QBrush::operator=(const QBrush &b)
return *this;
b.d->ref.ref();
- d.reset(b.d.data());
+ d.reset(b.d.get());
return *this;
}
@@ -672,7 +635,7 @@ QBrush &QBrush::operator=(const QBrush &b)
*/
QBrush::operator QVariant() const
{
- return QVariant(QMetaType::QBrush, this);
+ return QVariant::fromValue(*this);
}
/*!
@@ -748,7 +711,7 @@ void QBrush::setColor(const QColor &c)
QPixmap QBrush::texture() const
{
return d->style == Qt::TexturePattern
- ? (static_cast<QTexturedBrushData *>(d.data()))->pixmap()
+ ? (static_cast<QTexturedBrushData *>(d.get()))->pixmap()
: QPixmap();
}
@@ -766,7 +729,7 @@ void QBrush::setTexture(const QPixmap &pixmap)
{
if (!pixmap.isNull()) {
detach(Qt::TexturePattern);
- QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
+ QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
data->setPixmap(pixmap);
} else {
detach(Qt::NoBrush);
@@ -789,7 +752,7 @@ void QBrush::setTexture(const QPixmap &pixmap)
QImage QBrush::textureImage() const
{
return d->style == Qt::TexturePattern
- ? (static_cast<QTexturedBrushData *>(d.data()))->image()
+ ? (static_cast<QTexturedBrushData *>(d.get()))->image()
: QImage();
}
@@ -814,7 +777,7 @@ void QBrush::setTextureImage(const QImage &image)
{
if (!image.isNull()) {
detach(Qt::TexturePattern);
- QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data());
+ QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.get());
data->setImage(image);
} else {
detach(Qt::NoBrush);
@@ -830,7 +793,7 @@ const QGradient *QBrush::gradient() const
if (d->style == Qt::LinearGradientPattern
|| d->style == Qt::RadialGradientPattern
|| d->style == Qt::ConicalGradientPattern) {
- return &static_cast<const QGradientBrushData *>(d.data())->gradient;
+ return &static_cast<const QGradientBrushData *>(d.get())->gradient;
}
return nullptr;
}
@@ -866,7 +829,7 @@ Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
bool QBrush::isOpaque() const
{
- bool opaqueColor = d->color.alpha() == 255;
+ bool opaqueColor = d->color.alphaF() >= 1.0f;
// Test awfully simple case first
if (d->style == Qt::SolidPattern)
@@ -880,7 +843,7 @@ bool QBrush::isOpaque() const
|| d->style == Qt::ConicalGradientPattern) {
QGradientStops stops = gradient()->stops();
for (int i=0; i<stops.size(); ++i)
- if (stops.at(i).second.alpha() != 255)
+ if (stops.at(i).second.alphaF() < 1.0f)
return false;
return true;
} else if (d->style == Qt::TexturePattern) {
@@ -948,16 +911,16 @@ bool QBrush::operator==(const QBrush &b) const
const QPixmap *us = nullptr, *them = nullptr;
qint64 cacheKey1, cacheKey2;
if (qHasPixmapTexture(*this)) {
- us = (static_cast<QTexturedBrushData *>(d.data()))->m_pixmap;
+ us = (static_cast<QTexturedBrushData *>(d.get()))->m_pixmap;
cacheKey1 = us->cacheKey();
} else
- cacheKey1 = (static_cast<QTexturedBrushData *>(d.data()))->image().cacheKey();
+ cacheKey1 = (static_cast<QTexturedBrushData *>(d.get()))->image().cacheKey();
if (qHasPixmapTexture(b)) {
- them = (static_cast<QTexturedBrushData *>(b.d.data()))->m_pixmap;
+ them = (static_cast<QTexturedBrushData *>(b.d.get()))->m_pixmap;
cacheKey2 = them->cacheKey();
} else
- cacheKey2 = (static_cast<QTexturedBrushData *>(b.d.data()))->image().cacheKey();
+ cacheKey2 = (static_cast<QTexturedBrushData *>(b.d.get()))->image().cacheKey();
if (cacheKey1 != cacheKey2)
return false;
@@ -974,8 +937,8 @@ bool QBrush::operator==(const QBrush &b) const
case Qt::RadialGradientPattern:
case Qt::ConicalGradientPattern:
{
- const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data());
- const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data());
+ const QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.get());
+ const QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.get());
return d1->gradient == d2->gradient;
}
default:
@@ -989,7 +952,7 @@ bool QBrush::operator==(const QBrush &b) const
*/
QDebug operator<<(QDebug dbg, const QBrush &b)
{
- static const char BRUSH_STYLES[][24] = {
+ static constexpr auto BRUSH_STYLES = qOffsetStringArray(
"NoBrush",
"SolidPattern",
"Dense1Pattern",
@@ -1010,7 +973,7 @@ QDebug operator<<(QDebug dbg, const QBrush &b)
"ConicalGradientPattern",
"", "", "", "", "", "",
"TexturePattern" // 24
- };
+ );
QDebugStateSaver saver(dbg);
dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')';
@@ -1071,7 +1034,7 @@ QDataStream &operator<<(QDataStream &s, const QBrush &b)
// ensure that we write doubles here instead of streaming the stops
// directly; otherwise, platforms that redefine qreal might generate
// data that cannot be read on other platforms.
- QVector<QGradientStop> stops = gradient->stops();
+ QList<QGradientStop> stops = gradient->stops();
s << quint32(stops.size());
for (int i = 0; i < stops.size(); ++i) {
const QGradientStop &stop = stops.at(i);
@@ -1086,6 +1049,8 @@ QDataStream &operator<<(QDataStream &s, const QBrush &b)
s << static_cast<const QRadialGradient *>(gradient)->center();
s << static_cast<const QRadialGradient *>(gradient)->focalPoint();
s << (double) static_cast<const QRadialGradient *>(gradient)->radius();
+ if (s.version() >= QDataStream::Qt_6_0)
+ s << (double) static_cast<const QRadialGradient *>(gradient)->focalRadius();
} else { // type == Conical
s << static_cast<const QConicalGradient *>(gradient)->center();
s << (double) static_cast<const QConicalGradient *>(gradient)->angle();
@@ -1176,6 +1141,7 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
} else if (type == QGradient::RadialGradient) {
QPointF center, focal;
double radius;
+ double focalRadius = 0;
s >> center;
s >> focal;
s >> radius;
@@ -1184,6 +1150,9 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
rg.setSpread(spread);
rg.setCoordinateMode(cmode);
rg.setInterpolationMode(imode);
+ if (s.version() >= QDataStream::Qt_6_0)
+ s >> focalRadius;
+ rg.setFocalRadius(focalRadius);
b = QBrush(rg);
} else { // type == QGradient::ConicalGradient
QPointF center;
@@ -1271,7 +1240,7 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\snippet brush/brush.cpp 1
It is possible to repeat or reflect the gradient outside its area
- by specifiying the \l {QGradient::Spread}{spread method} using the
+ by specifying the \l {QGradient::Spread}{spread method} using the
setSpread() function. The default is to pad the outside area with
the color at the closest stop point. The currently set \l
{QGradient::Spread}{spread method} can be retrieved using the
@@ -1312,7 +1281,7 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\internal
*/
QGradient::QGradient()
- : m_type(NoGradient), dummy(nullptr)
+ : m_type(NoGradient)
{
}
@@ -1321,7 +1290,176 @@ QGradient::QGradient()
\since 5.12
This enum specifies a set of predefined presets for QGradient,
- based on the gradients from https://webgradients.com/.
+ based on the gradients from \l {https://webgradients.com/}.
+
+ \value WarmFlame
+ \value NightFade
+ \value SpringWarmth
+ \value JuicyPeach
+ \value YoungPassion
+ \value LadyLips
+ \value SunnyMorning
+ \value RainyAshville
+ \value FrozenDreams
+ \value WinterNeva
+ \value DustyGrass
+ \value TemptingAzure
+ \value HeavyRain
+ \value AmyCrisp
+ \value MeanFruit
+ \value DeepBlue
+ \value RipeMalinka
+ \value CloudyKnoxville
+ \value MalibuBeach
+ \value NewLife
+ \value TrueSunset
+ \value MorpheusDen
+ \value RareWind
+ \value NearMoon
+ \value WildApple
+ \value SaintPetersburg
+ \value PlumPlate
+ \value EverlastingSky
+ \value HappyFisher
+ \value Blessing
+ \value SharpeyeEagle
+ \value LadogaBottom
+ \value LemonGate
+ \value ItmeoBranding
+ \value ZeusMiracle
+ \value OldHat
+ \value StarWine
+ \value HappyAcid
+ \value AwesomePine
+ \value NewYork
+ \value ShyRainbow
+ \value MixedHopes
+ \value FlyHigh
+ \value StrongBliss
+ \value FreshMilk
+ \value SnowAgain
+ \value FebruaryInk
+ \value KindSteel
+ \value SoftGrass
+ \value GrownEarly
+ \value SharpBlues
+ \value ShadyWater
+ \value DirtyBeauty
+ \value GreatWhale
+ \value TeenNotebook
+ \value PoliteRumors
+ \value SweetPeriod
+ \value WideMatrix
+ \value SoftCherish
+ \value RedSalvation
+ \value BurningSpring
+ \value NightParty
+ \value SkyGlider
+ \value HeavenPeach
+ \value PurpleDivision
+ \value AquaSplash
+ \value SpikyNaga
+ \value LoveKiss
+ \value CleanMirror
+ \value PremiumDark
+ \value ColdEvening
+ \value CochitiLake
+ \value SummerGames
+ \value PassionateBed
+ \value MountainRock
+ \value DesertHump
+ \value JungleDay
+ \value PhoenixStart
+ \value OctoberSilence
+ \value FarawayRiver
+ \value AlchemistLab
+ \value OverSun
+ \value PremiumWhite
+ \value MarsParty
+ \value EternalConstance
+ \value JapanBlush
+ \value SmilingRain
+ \value CloudyApple
+ \value BigMango
+ \value HealthyWater
+ \value AmourAmour
+ \value RiskyConcrete
+ \value StrongStick
+ \value ViciousStance
+ \value PaloAlto
+ \value HappyMemories
+ \value MidnightBloom
+ \value Crystalline
+ \value PartyBliss
+ \value ConfidentCloud
+ \value LeCocktail
+ \value RiverCity
+ \value FrozenBerry
+ \value ChildCare
+ \value FlyingLemon
+ \value NewRetrowave
+ \value HiddenJaguar
+ \value AboveTheSky
+ \value Nega
+ \value DenseWater
+ \value Seashore
+ \value MarbleWall
+ \value CheerfulCaramel
+ \value NightSky
+ \value MagicLake
+ \value YoungGrass
+ \value ColorfulPeach
+ \value GentleCare
+ \value PlumBath
+ \value HappyUnicorn
+ \value AfricanField
+ \value SolidStone
+ \value OrangeJuice
+ \value GlassWater
+ \value NorthMiracle
+ \value FruitBlend
+ \value MillenniumPine
+ \value HighFlight
+ \value MoleHall
+ \value SpaceShift
+ \value ForestInei
+ \value RoyalGarden
+ \value RichMetal
+ \value JuicyCake
+ \value SmartIndigo
+ \value SandStrike
+ \value NorseBeauty
+ \value AquaGuidance
+ \value SunVeggie
+ \value SeaLord
+ \value BlackSea
+ \value GrassShampoo
+ \value LandingAircraft
+ \value WitchDance
+ \value SleeplessNight
+ \value AngelCare
+ \value CrystalRiver
+ \value SoftLipstick
+ \value SaltMountain
+ \value PerfectWhite
+ \value FreshOasis
+ \value StrictNovember
+ \value MorningSalad
+ \value DeepRelief
+ \value SeaStrike
+ \value NightCall
+ \value SupremeSky
+ \value LightBlue
+ \value MindCrawl
+ \value LilyMeadow
+ \value SugarLollipop
+ \value SweetDessert
+ \value MagicRay
+ \value TeenParty
+ \value FrozenHeat
+ \value GagarinView
+ \value FabledSunset
+ \value PerfectBlue
*/
#include "webgradients.cpp"
@@ -1338,10 +1476,9 @@ QGradient::QGradient()
*/
QGradient::QGradient(Preset preset)
: m_type(LinearGradient)
- , m_spread(PadSpread)
, m_stops(qt_preset_gradient_stops(preset))
, m_data(qt_preset_gradient_data[preset - 1])
- , dummy(qt_preset_gradient_dummy())
+ , m_coordinateMode(ObjectMode)
{
}
@@ -1470,7 +1607,6 @@ static inline bool ok(const QGradientStops &stops)
*/
void QGradient::setStops(const QGradientStops &stops)
{
- // ## Qt 6: consider taking \a stops by value, so we can move into m_stops
if (Q_LIKELY(ok(stops))) {
// fast path for the common case: if everything is ok with the stops, just copy them
m_stops = stops;
@@ -1495,15 +1631,14 @@ void QGradient::setStops(const QGradientStops &stops)
QGradientStops QGradient::stops() const
{
if (m_stops.isEmpty()) {
- QGradientStops tmp;
- tmp << QGradientStop(0, Qt::black) << QGradientStop(1, Qt::white);
- return tmp;
+ static constexpr QGradientStop blackAndWhite[] = {
+ {0, QColorConstants::Black}, {1, QColorConstants::White},
+ };
+ return QGradientStops::fromReadOnlyData(blackAndWhite);
}
return m_stops;
}
-#define Q_DUMMY_ACCESSOR union {void *p; uint i;}; p = dummy;
-
/*!
\enum QGradient::CoordinateMode
\since 4.4
@@ -1536,8 +1671,7 @@ QGradientStops QGradient::stops() const
*/
QGradient::CoordinateMode QGradient::coordinateMode() const
{
- Q_DUMMY_ACCESSOR
- return CoordinateMode(i & 0x03);
+ return m_coordinateMode;
}
/*!
@@ -1548,10 +1682,7 @@ QGradient::CoordinateMode QGradient::coordinateMode() const
*/
void QGradient::setCoordinateMode(CoordinateMode mode)
{
- Q_DUMMY_ACCESSOR
- i &= ~0x03;
- i |= uint(mode);
- dummy = p;
+ m_coordinateMode = mode;
}
/*!
@@ -1574,8 +1705,7 @@ void QGradient::setCoordinateMode(CoordinateMode mode)
*/
QGradient::InterpolationMode QGradient::interpolationMode() const
{
- Q_DUMMY_ACCESSOR
- return InterpolationMode((i >> 2) & 0x01);
+ return m_interpolationMode;
}
/*!
@@ -1587,10 +1717,7 @@ QGradient::InterpolationMode QGradient::interpolationMode() const
*/
void QGradient::setInterpolationMode(InterpolationMode mode)
{
- Q_DUMMY_ACCESSOR
- i &= ~(1 << 2);
- i |= (uint(mode) << 2);
- dummy = p;
+ m_interpolationMode = mode;
}
/*!
@@ -1613,7 +1740,8 @@ bool QGradient::operator==(const QGradient &gradient) const
{
if (gradient.m_type != m_type
|| gradient.m_spread != m_spread
- || gradient.dummy != dummy) return false;
+ || gradient.m_coordinateMode != m_coordinateMode
+ || gradient.m_interpolationMode != m_interpolationMode) return false;
if (m_type == LinearGradient) {
if (m_data.linear.x1 != gradient.m_data.linear.x1
@@ -1626,7 +1754,8 @@ bool QGradient::operator==(const QGradient &gradient) const
|| m_data.radial.cy != gradient.m_data.radial.cy
|| m_data.radial.fx != gradient.m_data.radial.fx
|| m_data.radial.fy != gradient.m_data.radial.fy
- || m_data.radial.cradius != gradient.m_data.radial.cradius)
+ || m_data.radial.cradius != gradient.m_data.radial.cradius
+ || m_data.radial.fradius != gradient.m_data.radial.fradius)
return false;
} else { // m_type == ConicalGradient
if (m_data.conical.cx != gradient.m_data.conical.cx
@@ -1900,6 +2029,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPoi
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
m_data.radial.cradius = radius;
+ m_data.radial.fradius = 0;
QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
m_data.radial.fx = adapted_focal.x();
@@ -1919,6 +2049,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
m_data.radial.cradius = radius;
+ m_data.radial.fradius = 0;
m_data.radial.fx = center.x();
m_data.radial.fy = center.y();
}
@@ -1964,6 +2095,7 @@ QRadialGradient::QRadialGradient()
m_data.radial.cx = 0;
m_data.radial.cy = 0;
m_data.radial.cradius = 1;
+ m_data.radial.fradius = 0;
m_data.radial.fx = 0;
m_data.radial.fy = 0;
}
@@ -1981,6 +2113,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, cons
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
m_data.radial.cradius = centerRadius;
+ m_data.radial.fradius = 0;
m_data.radial.fx = focalPoint.x();
m_data.radial.fy = focalPoint.y();
@@ -2001,6 +2134,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal f
m_data.radial.cx = cx;
m_data.radial.cy = cy;
m_data.radial.cradius = centerRadius;
+ m_data.radial.fradius = 0;
m_data.radial.fx = fx;
m_data.radial.fy = fy;
@@ -2120,12 +2254,7 @@ void QRadialGradient::setCenterRadius(qreal radius)
qreal QRadialGradient::focalRadius() const
{
Q_ASSERT(m_type == RadialGradient);
- Q_DUMMY_ACCESSOR
-
- // mask away low three bits
- union { float f; quint32 i; } u;
- u.i = i & ~0x07;
- return u.f;
+ return m_data.radial.fradius;
}
/*!
@@ -2137,17 +2266,7 @@ qreal QRadialGradient::focalRadius() const
void QRadialGradient::setFocalRadius(qreal radius)
{
Q_ASSERT(m_type == RadialGradient);
- Q_DUMMY_ACCESSOR
-
- // Since there's no QGradientData, we only have the dummy void * to
- // store additional data in. The three lowest bits are already
- // taken, thus we cut the three lowest bits from the significand
- // and store the radius as a float.
- union { float f; quint32 i; } u;
- u.f = float(radius);
- // add 0x04 to round up when we drop the three lowest bits
- i |= (u.i + 0x04) & ~0x07;
- dummy = p;
+ m_data.radial.fradius = radius;
}
/*!
@@ -2364,7 +2483,7 @@ void QConicalGradient::setAngle(qreal angle)
\typedef QGradientStops
\relates QGradient
- Typedef for QVector<QGradientStop>.
+ Typedef for QList<QGradientStop>.
*/
/*!
@@ -2392,6 +2511,6 @@ void QConicalGradient::setAngle(qreal angle)
\sa setTransform()
*/
-#undef Q_DUMMY_ACCESSOR
-
QT_END_NAMESPACE
+
+#include "moc_qbrush.cpp"
diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h
index 281789c838..ca8112ff31 100644
--- a/src/gui/painting/qbrush.h
+++ b/src/gui/painting/qbrush.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QBRUSH_H
#define QBRUSH_H
@@ -57,7 +21,10 @@ struct QBrushData;
class QPixmap;
class QGradient;
class QVariant;
-struct QBrushDataPointerDeleter;
+struct QBrushDataPointerDeleter
+{
+ void operator()(QBrushData *d) const noexcept;
+};
class Q_GUI_EXPORT QBrush
{
@@ -78,10 +45,9 @@ public:
~QBrush();
QBrush &operator=(const QBrush &brush);
- inline QBrush &operator=(QBrush &&other) noexcept
- { qSwap(d, other.d); return *this; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QBrush)
inline void swap(QBrush &other) noexcept
- { qSwap(d, other.d); }
+ { d.swap(other.d); }
operator QVariant() const;
@@ -108,6 +74,8 @@ public:
bool operator==(const QBrush &b) const;
inline bool operator!=(const QBrush &b) const { return !(operator==(b)); }
+ using DataPtr = std::unique_ptr<QBrushData, QBrushDataPointerDeleter>;
+
private:
friend class QRasterPaintEngine;
friend class QRasterPaintEnginePrivate;
@@ -116,12 +84,10 @@ private:
friend bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush);
void detach(Qt::BrushStyle newStyle);
void init(const QColor &color, Qt::BrushStyle bs);
- QScopedPointer<QBrushData, QBrushDataPointerDeleter> d;
- void cleanUp(QBrushData *x);
+ DataPtr d;
public:
inline bool isDetached() const;
- typedef QScopedPointer<QBrushData, QBrushDataPointerDeleter> DataPtr;
inline DataPtr &data_ptr() { return d; }
};
@@ -400,7 +366,7 @@ public:
qreal x1, y1, x2, y2;
} linear;
struct {
- qreal cx, cy, fx, fy, cradius;
+ qreal cx, cy, fx, fy, cradius, fradius;
} radial;
struct {
qreal cx, cy, angle;
@@ -413,11 +379,12 @@ private:
friend class QConicalGradient;
friend class QBrush;
- Type m_type;
- Spread m_spread;
+ Type m_type = NoGradient;
+ Spread m_spread = PadSpread;
QGradientStops m_stops;
QGradientData m_data;
- void *dummy; // ### Qt 6: replace with actual content (CoordinateMode, InterpolationMode, ...)
+ CoordinateMode m_coordinateMode = LogicalMode;
+ InterpolationMode m_interpolationMode = ColorInterpolation;
};
inline void QGradient::setSpread(Spread aspread)
diff --git a/src/gui/painting/qcmyk_p.h b/src/gui/painting/qcmyk_p.h
new file mode 100644
index 0000000000..d00a4b5a6e
--- /dev/null
+++ b/src/gui/painting/qcmyk_p.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCMYK_P_H
+#define QCMYK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCmyk32
+{
+private:
+ uint m_cmyk = 0;
+
+public:
+ QCmyk32() = default;
+
+ constexpr QCmyk32(int cyan, int magenta, int yellow, int black) :
+#if QT_BYTE_ORDER == Q_BIG_ENDIAN
+ m_cmyk(cyan << 24 | magenta << 16 | yellow << 8 | black)
+#else
+ m_cmyk(cyan | magenta << 8 | yellow << 16 | black << 24)
+#endif
+ {
+ }
+
+#if QT_BYTE_ORDER == Q_BIG_ENDIAN
+ constexpr int cyan() const noexcept { return (m_cmyk >> 24) & 0xff; }
+ constexpr int magenta() const noexcept { return (m_cmyk >> 16) & 0xff; }
+ constexpr int yellow() const noexcept { return (m_cmyk >> 8) & 0xff; }
+ constexpr int black() const noexcept { return (m_cmyk ) & 0xff; }
+#else
+ constexpr int cyan() const noexcept { return (m_cmyk ) & 0xff; }
+ constexpr int magenta() const noexcept { return (m_cmyk >> 8) & 0xff; }
+ constexpr int yellow() const noexcept { return (m_cmyk >> 16) & 0xff; }
+ constexpr int black() const noexcept { return (m_cmyk >> 24) & 0xff; }
+#endif
+
+ QColor toColor() const noexcept
+ {
+ return QColor::fromCmyk(cyan(), magenta(), yellow(), black());
+ }
+
+ constexpr uint toUint() const noexcept
+ {
+ return m_cmyk;
+ }
+
+ constexpr static QCmyk32 fromCmyk32(uint cmyk) noexcept
+ {
+ QCmyk32 result;
+ result.m_cmyk = cmyk;
+ return result;
+ }
+
+ static QCmyk32 fromRgba(QRgb rgba) noexcept
+ {
+ const QColor c = QColor(rgba).toCmyk();
+ return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black());
+ }
+
+ static QCmyk32 fromColor(const QColor &color) noexcept
+ {
+ QColor c = color.toCmyk();
+ return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black());
+ }
+};
+
+static_assert(sizeof(QCmyk32) == sizeof(int));
+static_assert(alignof(QCmyk32) == alignof(int));
+static_assert(std::is_standard_layout_v<QCmyk32>);
+
+QT_END_NAMESPACE
+
+#endif // QCMYK_P_H
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 06376f224b..2af2e8cb6b 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcolor.h"
#include "qcolor_p.h"
@@ -48,12 +12,19 @@
#include "private/qtools_p.h"
#include <algorithm>
+#include <optional>
#include <stdio.h>
#include <limits.h>
QT_BEGIN_NAMESPACE
+// QColor fits into QVariant's internal storage on 64bit systems.
+// It could also fit on 32bit systems, but we cannot make it happen in Qt6, due to BC.
+#if QT_VERSION >= QT_VERSION_CHECK(7,0,0) || QT_POINTER_SIZE > 4
+static_assert(sizeof(QColor) <= QVariant::Private::MaxInternalSize);
+#endif
+
/*!
\internal
If s[0..n] is a valid hex number, returns its integer value,
@@ -74,10 +45,10 @@ static inline int hex2int(const char *s, int n)
return result;
}
-static bool get_hex_rgb(const char *name, size_t len, QRgba64 *rgb)
+static std::optional<QRgba64> get_hex_rgb(const char *name, size_t len)
{
if (name[0] != '#')
- return false;
+ return std::nullopt;
name++;
--len;
int a, r, g, b;
@@ -90,6 +61,8 @@ static bool get_hex_rgb(const char *name, size_t len, QRgba64 *rgb)
r = hex2int(name + 0, 3);
g = hex2int(name + 3, 3);
b = hex2int(name + 6, 3);
+ if (r == -1 || g == -1 || b == -1)
+ return std::nullopt;
r = (r << 4) | (r >> 8);
g = (g << 4) | (g >> 8);
b = (b << 4) | (b >> 8);
@@ -109,32 +82,34 @@ static bool get_hex_rgb(const char *name, size_t len, QRgba64 *rgb)
} else {
r = g = b = -1;
}
- if ((uint)r > 65535 || (uint)g > 65535 || (uint)b > 65535 || (uint)a > 65535) {
- *rgb = 0;
- return false;
- }
- *rgb = qRgba64(r, g ,b, a);
- return true;
+ if (uint(r) > 65535 || uint(g) > 65535 || uint(b) > 65535 || uint(a) > 65535)
+ return std::nullopt;
+ return qRgba64(r, g ,b, a);
}
-bool qt_get_hex_rgb(const char *name, QRgb *rgb)
+std::optional<QRgb> qt_get_hex_rgb(const char *name)
{
- QRgba64 rgba64;
- if (!get_hex_rgb(name, qstrlen(name), &rgba64))
- return false;
- *rgb = rgba64.toArgb32();
- return true;
+ if (std::optional<QRgba64> rgba64 = get_hex_rgb(name, qstrlen(name)))
+ return rgba64->toArgb32();
+ return std::nullopt;
}
-static bool get_hex_rgb(const QChar *str, size_t len, QRgba64 *rgb)
+static std::optional<QRgba64> get_hex_rgb(const QChar *str, size_t len)
{
if (len > 13)
- return false;
+ return std::nullopt;
char tmp[16];
for (size_t i = 0; i < len; ++i)
tmp[i] = str[i].toLatin1();
tmp[len] = 0;
- return get_hex_rgb(tmp, len, rgb);
+ return get_hex_rgb(tmp, len);
+}
+
+static std::optional<QRgba64> get_hex_rgb(QAnyStringView name)
+{
+ return name.visit([] (auto name) {
+ return get_hex_rgb(name.data(), name.size());
+ });
}
#ifndef QT_NO_COLORNAMES
@@ -149,7 +124,7 @@ static bool get_hex_rgb(const QChar *str, size_t len, QRgba64 *rgb)
#define rgb(r,g,b) (0xff000000 | (r << 16) | (g << 8) | b)
// keep this is in sync with QColorConstants
-static const struct RGBData {
+static constexpr struct RGBData {
const char name[21];
uint value;
} rgbTbl[] = {
@@ -305,6 +280,16 @@ static const struct RGBData {
static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData);
+static_assert([] {
+ for (auto e : rgbTbl) {
+ for (auto it = e.name; *it ; ++it) {
+ if (uchar(*it) > 127)
+ return false;
+ }
+ }
+ return true;
+ }(), "the lookup code expects color names to be US-ASCII-only");
+
#undef rgb
inline bool operator<(const char *name, const RGBData &data)
@@ -312,43 +297,35 @@ inline bool operator<(const char *name, const RGBData &data)
inline bool operator<(const RGBData &data, const char *name)
{ return qstrcmp(data.name, name) < 0; }
-static bool get_named_rgb_no_space(const char *name_no_space, QRgb *rgb)
+static std::optional<QRgb> get_named_rgb_no_space(const char *name_no_space)
{
const RGBData *r = std::lower_bound(rgbTbl, rgbTbl + rgbTblSize, name_no_space);
- if ((r != rgbTbl + rgbTblSize) && !(name_no_space < *r)) {
- *rgb = r->value;
- return true;
- }
- return false;
+ if ((r != rgbTbl + rgbTblSize) && !(name_no_space < *r))
+ return r->value;
+ return std::nullopt;
}
-static bool get_named_rgb(const char *name, int len, QRgb* rgb)
-{
- if (len > 255)
- return false;
- char name_no_space[256];
- int pos = 0;
- for (int i = 0; i < len; i++) {
- if (name[i] != '\t' && name[i] != ' ')
- name_no_space[pos++] = QChar::toLower(name[i]);
- }
- name_no_space[pos] = 0;
-
- return get_named_rgb_no_space(name_no_space, rgb);
+namespace {
+// named colors are US-ASCII (enforced by static_assert above):
+static char to_char(char ch) noexcept { return ch; }
+static char to_char(QChar ch) noexcept { return ch.toLatin1(); }
}
-static bool get_named_rgb(const QChar *name, int len, QRgb *rgb)
+static std::optional<QRgb> get_named_rgb(QAnyStringView name)
{
- if (len > 255)
- return false;
+ if (name.size() > 255)
+ return std::nullopt;
char name_no_space[256];
int pos = 0;
- for (int i = 0; i < len; i++) {
- if (name[i] != QLatin1Char('\t') && name[i] != QLatin1Char(' '))
- name_no_space[pos++] = name[i].toLower().toLatin1();
- }
+ name.visit([&pos, &name_no_space] (auto name) {
+ for (auto c : name) {
+ if (c != u'\t' && c != u' ')
+ name_no_space[pos++] = QtMiscUtils::toAsciiLower(to_char(c));
+ }
+ });
name_no_space[pos] = 0;
- return get_named_rgb_no_space(name_no_space, rgb);
+
+ return get_named_rgb_no_space(name_no_space);
}
#endif // QT_NO_COLORNAMES
@@ -359,7 +336,7 @@ static QStringList get_colornames()
#ifndef QT_NO_COLORNAMES
lst.reserve(rgbTblSize);
for (int i = 0; i < rgbTblSize; i++)
- lst << QLatin1String(rgbTbl[i].name);
+ lst << QLatin1StringView(rgbTbl[i].name);
#endif
return lst;
}
@@ -403,7 +380,7 @@ static QStringList get_colornames()
A color can be set by passing an RGB string (such as "#112233"),
or an ARGB string (such as "#ff112233") or a color name (such as "blue"),
- to the setNamedColor() function.
+ to the fromString() function.
The color names are taken from the SVG 1.0 color names. The name()
function returns the name of the color in the format
"#RRGGBB". Colors can also be set using setRgb(), setHsv() and
@@ -470,7 +447,7 @@ static QStringList get_colornames()
The alpha channel of a color can be retrieved and set using the
alpha() and setAlpha() functions if its value is an integer, and
- alphaF() and setAlphaF() if its value is qreal (double). By
+ alphaF() and setAlphaF() if its value is float. By
default, the alpha-channel is set to 255 (opaque). To retrieve and
set \e all the RGB color components (including the alpha-channel)
in one go, use the rgba() and setRgba() functions.
@@ -611,9 +588,9 @@ static QStringList get_colornames()
#define QCOLOR_REAL_RANGE_CHECK(fn, var) \
do { \
- if (var < qreal(0.0) || var > qreal(1.0)) { \
+ if (var < 0.0f || var > 1.0f) { \
qWarning(#fn": invalid value %g", var); \
- var = qMax(qreal(0.0), qMin(var, qreal(1.0))); \
+ var = qMax(0.0f, qMin(var, 1.0f)); \
} \
} while (0)
@@ -778,7 +755,7 @@ QColor::QColor(QRgba64 rgba64) noexcept
Constructs a color with the given \a spec.
- This function is primarly present to avoid that QColor::Invalid
+ This function is primarily present to avoid that QColor::Invalid
becomes a valid color by accident.
*/
@@ -807,6 +784,7 @@ QColor::QColor(Spec spec) noexcept
}
}
+// ### Qt 7: remove those after deprecating them for the last Qt 6 LTS release
/*!
\fn QColor::QColor(const QString &name)
@@ -829,7 +807,7 @@ QColor::QColor(Spec spec) noexcept
*/
/*!
- \fn QColor::QColor(QLatin1String name)
+ \fn QColor::QColor(QLatin1StringView name)
Constructs a named color in the same way as setNamedColor() using
the given \a name.
@@ -839,16 +817,6 @@ QColor::QColor(Spec spec) noexcept
\sa setNamedColor(), name(), isValid()
*/
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
-/*!
- \fn QColor::QColor(const QColor &color)
-
- Constructs a color that is a copy of \a color.
-
- \sa isValid()
-*/
-#endif
-
/*!
\fn bool QColor::isValid() const
@@ -860,23 +828,25 @@ QColor::QColor(Spec spec) noexcept
Returns the name of the color in the specified \a format.
- \sa setNamedColor(), NameFormat
+ \sa fromString(), NameFormat
*/
QString QColor::name(NameFormat format) const
{
switch (format) {
case HexRgb:
- return QLatin1Char('#') + QStringView{QString::number(rgba() | 0x1000000, 16)}.right(6);
+ return u'#' + QStringView{QString::number(rgba() | 0x1000000, 16)}.right(6);
case HexArgb:
// it's called rgba() but it does return AARRGGBB
- return QLatin1Char('#') + QStringView{QString::number(rgba() | Q_INT64_C(0x100000000), 16)}.right(8);
+ return u'#' + QStringView{QString::number(rgba() | Q_INT64_C(0x100000000), 16)}.right(8);
}
return QString();
}
-#if QT_STRINGVIEW_LEVEL < 2
+#if QT_DEPRECATED_SINCE(6, 6)
/*!
+ \deprecated [6.6] Use fromString() instead.
+
Sets the RGB value of this QColor to \a name, which may be in one
of these formats:
@@ -902,34 +872,36 @@ QString QColor::name(NameFormat format) const
void QColor::setNamedColor(const QString &name)
{
- setColorFromString(qToStringViewIgnoringNull(name));
+ *this = fromString(qToAnyStringViewIgnoringNull(name));
}
-#endif
/*!
\overload
\since 5.10
+ \deprecated [6.6] Use fromString() instead.
*/
void QColor::setNamedColor(QStringView name)
{
- setColorFromString(name);
+ *this = fromString(name);
}
/*!
\overload
\since 5.8
+ \deprecated [6.6] Use fromString() instead.
*/
-void QColor::setNamedColor(QLatin1String name)
+void QColor::setNamedColor(QLatin1StringView name)
{
- setColorFromString(name);
+ *this = fromString(name);
}
-#if QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.7
+ \deprecated [6.6] Use isValidColorName() instead.
+
Returns \c true if the \a name is a valid color name and can
be used to construct a valid QColor object, otherwise returns
false.
@@ -940,58 +912,86 @@ void QColor::setNamedColor(QLatin1String name)
*/
bool QColor::isValidColor(const QString &name)
{
- return isValidColor(qToStringViewIgnoringNull(name));
+ return isValidColorName(qToAnyStringViewIgnoringNull(name));
}
-#endif
/*!
\overload
\since 5.10
+ \deprecated [6.6] Use isValidColorName() instead.
*/
bool QColor::isValidColor(QStringView name) noexcept
{
- return name.size() && QColor().setColorFromString(name);
+ return isValidColorName(name);
}
/*!
\overload
\since 5.8
+ \deprecated [6.6] Use isValidColorName() instead.
*/
-bool QColor::isValidColor(QLatin1String name) noexcept
+bool QColor::isValidColor(QLatin1StringView name) noexcept
{
- return name.size() && QColor().setColorFromString(name);
+ return isValidColorName(name);
}
+#endif // QT_DEPRECATED_SINCE(6, 6)
-template <typename String>
-bool QColor::setColorFromString(String name)
+/*!
+ \since 6.4
+
+ Returns \c true if the \a name is a valid color name and can
+ be used to construct a valid QColor object, otherwise returns
+ false.
+
+ It uses the same algorithm used in fromString().
+
+ \sa fromString()
+*/
+bool QColor::isValidColorName(QAnyStringView name) noexcept
{
- if (!name.size()) {
- invalidate();
- return true;
- }
+ return fromString(name).isValid();
+}
- if (name[0] == QLatin1Char('#')) {
- QRgba64 rgba;
- if (get_hex_rgb(name.data(), name.size(), &rgba)) {
- setRgba64(rgba);
- return true;
- } else {
- invalidate();
- return false;
- }
- }
+/*!
+ \since 6.4
+ Returns an RGB QColor parsed from \a name, which may be in one
+ of these formats:
+
+ \list
+ \li #RGB (each of R, G, and B is a single hex digit)
+ \li #RRGGBB
+ \li #AARRGGBB (Since 5.2)
+ \li #RRRGGGBBB
+ \li #RRRRGGGGBBBB
+ \li A name from the list of colors defined in the list of
+ \l{https://www.w3.org/TR/SVG11/types.html#ColorKeywords}{SVG color keyword names}
+ provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
+ These color names work on all platforms. Note that these color names are \e not the
+ same as defined by the Qt::GlobalColor enums, e.g. "green" and Qt::green does not
+ refer to the same color.
+ \li \c transparent - representing the absence of a color.
+ \endlist
+
+ Returns an invalid color if \a name cannot be parsed.
+
+ \sa isValidColorName()
+*/
+QColor QColor::fromString(QAnyStringView name) noexcept
+{
+ if (!name.size())
+ return {};
+
+ if (name.front() == u'#') {
+ if (std::optional<QRgba64> r = get_hex_rgb(name))
+ return QColor::fromRgba64(*r);
#ifndef QT_NO_COLORNAMES
- QRgb rgb;
- if (get_named_rgb(name.data(), name.size(), &rgb)) {
- setRgba(rgb);
- return true;
- } else
+ } else if (std::optional<QRgb> r = get_named_rgb(name)) {
+ return QColor::fromRgba(*r);
#endif
- {
- invalidate();
- return false;
}
+
+ return {};
}
/*!
@@ -1014,7 +1014,7 @@ QStringList QColor::colorNames()
\sa setHsv(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-void QColor::getHsvF(qreal *h, qreal *s, qreal *v, qreal *a) const
+void QColor::getHsvF(float *h, float *s, float *v, float *a) const
{
if (!h || !s || !v)
return;
@@ -1024,12 +1024,12 @@ void QColor::getHsvF(qreal *h, qreal *s, qreal *v, qreal *a) const
return;
}
- *h = ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0);
- *s = ct.ahsv.saturation / qreal(USHRT_MAX);
- *v = ct.ahsv.value / qreal(USHRT_MAX);
+ *h = ct.ahsv.hue == USHRT_MAX ? -1.0f : ct.ahsv.hue / 36000.0f;
+ *s = ct.ahsv.saturation / float(USHRT_MAX);
+ *v = ct.ahsv.value / float(USHRT_MAX);
if (a)
- *a = ct.ahsv.alpha / qreal(USHRT_MAX);
+ *a = ct.ahsv.alpha / float(USHRT_MAX);
}
/*!
@@ -1068,12 +1068,12 @@ void QColor::getHsv(int *h, int *s, int *v, int *a) const
\sa getHsvF(), setHsv(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-void QColor::setHsvF(qreal h, qreal s, qreal v, qreal a)
+void QColor::setHsvF(float h, float s, float v, float a)
{
- if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0))
- || (s < qreal(0.0) || s > qreal(1.0))
- || (v < qreal(0.0) || v > qreal(1.0))
- || (a < qreal(0.0) || a > qreal(1.0))) {
+ if (((h < 0.0f || h > 1.0f) && h != -1.0f)
+ || (s < 0.0f || s > 1.0f)
+ || (v < 0.0f || v > 1.0f)
+ || (a < 0.0f || a > 1.0f)) {
qWarning("QColor::setHsvF: HSV parameters out of range");
invalidate();
return;
@@ -1081,7 +1081,7 @@ void QColor::setHsvF(qreal h, qreal s, qreal v, qreal a)
cspec = Hsv;
ct.ahsv.alpha = qRound(a * USHRT_MAX);
- ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000);
+ ct.ahsv.hue = h == -1.0f ? USHRT_MAX : qRound(h * 36000.0f);
ct.ahsv.saturation = qRound(s * USHRT_MAX);
ct.ahsv.value = qRound(v * USHRT_MAX);
ct.ahsv.pad = 0;
@@ -1124,7 +1124,7 @@ void QColor::setHsv(int h, int s, int v, int a)
\sa getHsl(), setHslF(), {QColor#The HSL Color Model}{The HSL Color Model}
*/
-void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const
+void QColor::getHslF(float *h, float *s, float *l, float *a) const
{
if (!h || !s || !l)
return;
@@ -1134,12 +1134,12 @@ void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const
return;
}
- *h = ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0);
- *s = ct.ahsl.saturation / qreal(USHRT_MAX);
- *l = ct.ahsl.lightness / qreal(USHRT_MAX);
+ *h = ct.ahsl.hue == USHRT_MAX ? -1.0f : ct.ahsl.hue / 36000.0f;
+ *s = ct.ahsl.saturation / float(USHRT_MAX);
+ *l = ct.ahsl.lightness / float(USHRT_MAX);
if (a)
- *a = ct.ahsl.alpha / qreal(USHRT_MAX);
+ *a = ct.ahsl.alpha / float(USHRT_MAX);
}
/*!
@@ -1182,12 +1182,12 @@ void QColor::getHsl(int *h, int *s, int *l, int *a) const
\sa getHslF(), setHsl()
*/
-void QColor::setHslF(qreal h, qreal s, qreal l, qreal a)
+void QColor::setHslF(float h, float s, float l, float a)
{
- if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0))
- || (s < qreal(0.0) || s > qreal(1.0))
- || (l < qreal(0.0) || l > qreal(1.0))
- || (a < qreal(0.0) || a > qreal(1.0))) {
+ if (((h < 0.0f || h > 1.0f) && h != -1.0f)
+ || (s < 0.0f || s > 1.0f)
+ || (l < 0.0f || l > 1.0f)
+ || (a < 0.0f || a > 1.0f)) {
qWarning("QColor::setHslF: HSL parameters out of range");
invalidate();
return;
@@ -1195,7 +1195,7 @@ void QColor::setHslF(qreal h, qreal s, qreal l, qreal a)
cspec = Hsl;
ct.ahsl.alpha = qRound(a * USHRT_MAX);
- ct.ahsl.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000);
+ ct.ahsl.hue = h == -1.0f ? USHRT_MAX : qRound(h * 36000.0f);
ct.ahsl.saturation = qRound(s * USHRT_MAX);
ct.ahsl.lightness = qRound(l * USHRT_MAX);
ct.ahsl.pad = 0;
@@ -1249,25 +1249,22 @@ static inline const qfloat16 &castF16(const quint16 &v)
\sa rgb(), setRgb()
*/
-void QColor::getRgbF(qreal *r, qreal *g, qreal *b, qreal *a) const
+void QColor::getRgbF(float *r, float *g, float *b, float *a) const
{
if (!r || !g || !b)
return;
- if (cspec == Invalid)
- return;
-
- if (cspec != Rgb && cspec != ExtendedRgb) {
+ if (cspec != Invalid && cspec != Rgb && cspec != ExtendedRgb) {
toRgb().getRgbF(r, g, b, a);
return;
}
- if (cspec == Rgb) {
- *r = ct.argb.red / qreal(USHRT_MAX);
- *g = ct.argb.green / qreal(USHRT_MAX);
- *b = ct.argb.blue / qreal(USHRT_MAX);
+ if (cspec == Rgb || cspec == Invalid) {
+ *r = ct.argb.red / float(USHRT_MAX);
+ *g = ct.argb.green / float(USHRT_MAX);
+ *b = ct.argb.blue / float(USHRT_MAX);
if (a)
- *a = ct.argb.alpha / qreal(USHRT_MAX);
+ *a = ct.argb.alpha / float(USHRT_MAX);
} else {
*r = castF16(ct.argbExtended.redF16);
*g = castF16(ct.argbExtended.greenF16);
@@ -1306,7 +1303,7 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const
}
/*!
- \fn void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a)
+ \fn void QColor::setRgbF(float r, float g, float b, float a)
Sets the color channels of this color to \a r (red), \a g (green),
\a b (blue) and \a a (alpha, transparency).
@@ -1317,16 +1314,16 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const
\sa rgb(), getRgbF(), setRgb()
*/
-void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a)
+void QColor::setRgbF(float r, float g, float b, float a)
{
- if (a < qreal(0.0) || a > qreal(1.0)) {
+ if (a < 0.0f || a > 1.0f) {
qWarning("QColor::setRgbF: Alpha parameter is out of range");
invalidate();
return;
}
- if (r < qreal(0.0) || r > qreal(1.0) ||
- g < qreal(0.0) || g > qreal(1.0) ||
- b < qreal(0.0) || b > qreal(1.0) || cspec == ExtendedRgb) {
+ if (r < 0.0f || r > 1.0f ||
+ g < 0.0f || g > 1.0f ||
+ b < 0.0f || b > 1.0f || cspec == ExtendedRgb) {
cspec = ExtendedRgb;
castF16(ct.argbExtended.redF16) = qfloat16(r);
castF16(ct.argbExtended.greenF16) = qfloat16(g);
@@ -1469,7 +1466,7 @@ void QColor::setRgb(QRgb rgb) noexcept
int QColor::alpha() const noexcept
{
if (cspec == ExtendedRgb)
- return qRound(qreal(castF16(ct.argbExtended.alphaF16)) * 255);
+ return qRound(float(castF16(ct.argbExtended.alphaF16)) * 255);
return qt_div_257(ct.argb.alpha);
}
@@ -1485,8 +1482,8 @@ void QColor::setAlpha(int alpha)
{
QCOLOR_INT_RANGE_CHECK("QColor::setAlpha", alpha);
if (cspec == ExtendedRgb) {
- constexpr qreal f = qreal(1.0) / 255;
- castF16(ct.argbExtended.alphaF16) = alpha * f;
+ constexpr float f = 1.0f / 255;
+ castF16(ct.argbExtended.alphaF16) = qfloat16(alpha * f);
return;
}
ct.argb.alpha = alpha * 0x101;
@@ -1497,28 +1494,28 @@ void QColor::setAlpha(int alpha)
\sa setAlphaF(), alpha(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing}
*/
-qreal QColor::alphaF() const noexcept
+float QColor::alphaF() const noexcept
{
if (cspec == ExtendedRgb)
return castF16(ct.argbExtended.alphaF16);
- return ct.argb.alpha / qreal(USHRT_MAX);
+ return ct.argb.alpha / float(USHRT_MAX);
}
/*!
- Sets the alpha of this color to \a alpha. qreal alpha is specified in the
+ Sets the alpha of this color to \a alpha. float alpha is specified in the
range 0.0-1.0.
\sa alphaF(), alpha(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing}
*/
-void QColor::setAlphaF(qreal alpha)
+void QColor::setAlphaF(float alpha)
{
QCOLOR_REAL_RANGE_CHECK("QColor::setAlphaF", alpha);
if (cspec == ExtendedRgb) {
- castF16(ct.argbExtended.alphaF16) = alpha;
+ castF16(ct.argbExtended.alphaF16) = qfloat16(alpha);
return;
}
- qreal tmp = alpha * USHRT_MAX;
+ float tmp = alpha * USHRT_MAX;
ct.argb.alpha = qRound(tmp);
}
@@ -1611,10 +1608,10 @@ void QColor::setBlue(int blue)
\sa setRedF(), red(), getRgbF()
*/
-qreal QColor::redF() const noexcept
+float QColor::redF() const noexcept
{
if (cspec == Rgb || cspec == Invalid)
- return ct.argb.red / qreal(USHRT_MAX);
+ return ct.argb.red / float(USHRT_MAX);
if (cspec == ExtendedRgb)
return castF16(ct.argbExtended.redF16);
@@ -1628,12 +1625,12 @@ qreal QColor::redF() const noexcept
\sa redF(), red(), setRgbF()
*/
-void QColor::setRedF(qreal red)
+void QColor::setRedF(float red)
{
- if (cspec == Rgb && red >= qreal(0.0) && red <= qreal(1.0))
+ if (cspec == Rgb && red >= 0.0f && red <= 1.0f)
ct.argb.red = qRound(red * USHRT_MAX);
else if (cspec == ExtendedRgb)
- castF16(ct.argbExtended.redF16) = red;
+ castF16(ct.argbExtended.redF16) = qfloat16(red);
else
setRgbF(red, greenF(), blueF(), alphaF());
}
@@ -1643,10 +1640,10 @@ void QColor::setRedF(qreal red)
\sa setGreenF(), green(), getRgbF()
*/
-qreal QColor::greenF() const noexcept
+float QColor::greenF() const noexcept
{
if (cspec == Rgb || cspec == Invalid)
- return ct.argb.green / qreal(USHRT_MAX);
+ return ct.argb.green / float(USHRT_MAX);
if (cspec == ExtendedRgb)
return castF16(ct.argbExtended.greenF16);
@@ -1660,12 +1657,12 @@ qreal QColor::greenF() const noexcept
\sa greenF(), green(), setRgbF()
*/
-void QColor::setGreenF(qreal green)
+void QColor::setGreenF(float green)
{
- if (cspec == Rgb && green >= qreal(0.0) && green <= qreal(1.0))
+ if (cspec == Rgb && green >= 0.0f && green <= 1.0f)
ct.argb.green = qRound(green * USHRT_MAX);
else if (cspec == ExtendedRgb)
- castF16(ct.argbExtended.greenF16) = green;
+ castF16(ct.argbExtended.greenF16) = qfloat16(green);
else
setRgbF(redF(), green, blueF(), alphaF());
}
@@ -1675,10 +1672,10 @@ void QColor::setGreenF(qreal green)
\sa setBlueF(), blue(), getRgbF()
*/
-qreal QColor::blueF() const noexcept
+float QColor::blueF() const noexcept
{
if (cspec == Rgb || cspec == Invalid)
- return ct.argb.blue / qreal(USHRT_MAX);
+ return ct.argb.blue / float(USHRT_MAX);
if (cspec == ExtendedRgb)
return castF16(ct.argbExtended.blueF16);
@@ -1690,12 +1687,12 @@ qreal QColor::blueF() const noexcept
the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb.
\sa blueF(), blue(), setRgbF()
*/
-void QColor::setBlueF(qreal blue)
+void QColor::setBlueF(float blue)
{
- if (cspec == Rgb && blue >= qreal(0.0) && blue <= qreal(1.0))
+ if (cspec == Rgb && blue >= 0.0f && blue <= 1.0f)
ct.argb.blue = qRound(blue * USHRT_MAX);
else if (cspec == ExtendedRgb)
- castF16(ct.argbExtended.blueF16) = blue;
+ castF16(ct.argbExtended.blueF16) = qfloat16(blue);
else
setRgbF(redF(), greenF(), blue, alphaF());
}
@@ -1770,7 +1767,7 @@ int QColor::value() const noexcept
\sa hsvHueF(), hslHueF(), hue(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-qreal QColor::hueF() const noexcept
+float QColor::hueF() const noexcept
{
return hsvHueF();
}
@@ -1781,11 +1778,11 @@ qreal QColor::hueF() const noexcept
\sa hue(), hslHueF(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color
Model}
*/
-qreal QColor::hsvHueF() const noexcept
+float QColor::hsvHueF() const noexcept
{
if (cspec != Invalid && cspec != Hsv)
return toHsv().hueF();
- return ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0);
+ return ct.ahsv.hue == USHRT_MAX ? -1.0f : ct.ahsv.hue / 36000.0f;
}
/*!
@@ -1796,7 +1793,7 @@ qreal QColor::hsvHueF() const noexcept
\sa hsvSaturationF(), hslSaturationF(), saturation(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color
Model}
*/
-qreal QColor::saturationF() const noexcept
+float QColor::saturationF() const noexcept
{
return hsvSaturationF();
}
@@ -1806,11 +1803,11 @@ qreal QColor::saturationF() const noexcept
\sa saturation(), hslSaturationF(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-qreal QColor::hsvSaturationF() const noexcept
+float QColor::hsvSaturationF() const noexcept
{
if (cspec != Invalid && cspec != Hsv)
return toHsv().saturationF();
- return ct.ahsv.saturation / qreal(USHRT_MAX);
+ return ct.ahsv.saturation / float(USHRT_MAX);
}
/*!
@@ -1818,11 +1815,11 @@ qreal QColor::hsvSaturationF() const noexcept
\sa value(), getHsvF(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-qreal QColor::valueF() const noexcept
+float QColor::valueF() const noexcept
{
if (cspec != Invalid && cspec != Hsv)
return toHsv().valueF();
- return ct.ahsv.value / qreal(USHRT_MAX);
+ return ct.ahsv.value / float(USHRT_MAX);
}
/*!
@@ -1874,11 +1871,11 @@ int QColor::lightness() const noexcept
\sa hslHue(), hsvHueF(), getHslF()
*/
-qreal QColor::hslHueF() const noexcept
+float QColor::hslHueF() const noexcept
{
if (cspec != Invalid && cspec != Hsl)
return toHsl().hslHueF();
- return ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0);
+ return ct.ahsl.hue == USHRT_MAX ? -1.0f : ct.ahsl.hue / 36000.0f;
}
/*!
@@ -1888,11 +1885,11 @@ qreal QColor::hslHueF() const noexcept
\sa hslSaturation(), hsvSaturationF(), getHslF(), {QColor#The HSL Color Model}{The HSL Color Model}
*/
-qreal QColor::hslSaturationF() const noexcept
+float QColor::hslSaturationF() const noexcept
{
if (cspec != Invalid && cspec != Hsl)
return toHsl().hslSaturationF();
- return ct.ahsl.saturation / qreal(USHRT_MAX);
+ return ct.ahsl.saturation / float(USHRT_MAX);
}
/*!
@@ -1902,11 +1899,11 @@ qreal QColor::hslSaturationF() const noexcept
\sa value(), getHslF()
*/
-qreal QColor::lightnessF() const noexcept
+float QColor::lightnessF() const noexcept
{
if (cspec != Invalid && cspec != Hsl)
return toHsl().lightnessF();
- return ct.ahsl.lightness / qreal(USHRT_MAX);
+ return ct.ahsl.lightness / float(USHRT_MAX);
}
/*!
@@ -1963,11 +1960,11 @@ int QColor::black() const noexcept
\sa cyan(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-qreal QColor::cyanF() const noexcept
+float QColor::cyanF() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().cyanF();
- return ct.acmyk.cyan / qreal(USHRT_MAX);
+ return ct.acmyk.cyan / float(USHRT_MAX);
}
/*!
@@ -1975,11 +1972,11 @@ qreal QColor::cyanF() const noexcept
\sa magenta(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-qreal QColor::magentaF() const noexcept
+float QColor::magentaF() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().magentaF();
- return ct.acmyk.magenta / qreal(USHRT_MAX);
+ return ct.acmyk.magenta / float(USHRT_MAX);
}
/*!
@@ -1987,11 +1984,11 @@ qreal QColor::magentaF() const noexcept
\sa yellow(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-qreal QColor::yellowF() const noexcept
+float QColor::yellowF() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().yellowF();
- return ct.acmyk.yellow / qreal(USHRT_MAX);
+ return ct.acmyk.yellow / float(USHRT_MAX);
}
/*!
@@ -1999,11 +1996,11 @@ qreal QColor::yellowF() const noexcept
\sa black(), getCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-qreal QColor::blackF() const noexcept
+float QColor::blackF() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().blackF();
- return ct.acmyk.black / qreal(USHRT_MAX);
+ return ct.acmyk.black / float(USHRT_MAX);
}
/*!
@@ -2019,7 +2016,7 @@ QColor QColor::toExtendedRgb() const noexcept
if (cspec != Rgb)
return toRgb().toExtendedRgb();
- constexpr qreal f = qreal(1.0) / USHRT_MAX;
+ constexpr float f = 1.0f / USHRT_MAX;
QColor color;
color.cspec = ExtendedRgb;
castF16(color.ct.argbExtended.alphaF16) = qfloat16(ct.argb.alpha * f);
@@ -2056,15 +2053,15 @@ QColor QColor::toRgb() const noexcept
}
// chromatic case
- const qreal h = ct.ahsv.hue == 36000 ? 0 : ct.ahsv.hue / 6000.;
- const qreal s = ct.ahsv.saturation / qreal(USHRT_MAX);
- const qreal v = ct.ahsv.value / qreal(USHRT_MAX);
+ const float h = ct.ahsv.hue == 36000 ? 0.0f : ct.ahsv.hue / 6000.0f;
+ const float s = ct.ahsv.saturation / float(USHRT_MAX);
+ const float v = ct.ahsv.value / float(USHRT_MAX);
const int i = int(h);
- const qreal f = h - i;
- const qreal p = v * (qreal(1.0) - s);
+ const float f = h - i;
+ const float p = v * (1.0f - s);
if (i & 1) {
- const qreal q = v * (qreal(1.0) - (s * f));
+ const float q = v * (1.0f - (s * f));
switch (i) {
case 1:
@@ -2084,7 +2081,7 @@ QColor QColor::toRgb() const noexcept
break;
}
} else {
- const qreal t = v * (qreal(1.0) - (s * (qreal(1.0) - f)));
+ const float t = v * (1.0f - (s * (1.0f - f)));
switch (i) {
case 0:
@@ -2116,34 +2113,34 @@ QColor QColor::toRgb() const noexcept
color.ct.argb.red = color.ct.argb.green = color.ct.argb.blue = 0;
} else {
// chromatic case
- const qreal h = ct.ahsl.hue == 36000 ? 0 : ct.ahsl.hue / 36000.;
- const qreal s = ct.ahsl.saturation / qreal(USHRT_MAX);
- const qreal l = ct.ahsl.lightness / qreal(USHRT_MAX);
+ const float h = ct.ahsl.hue == 36000 ? 0.0f : ct.ahsl.hue / 36000.0f;
+ const float s = ct.ahsl.saturation / float(USHRT_MAX);
+ const float l = ct.ahsl.lightness / float(USHRT_MAX);
- qreal temp2;
- if (l < qreal(0.5))
- temp2 = l * (qreal(1.0) + s);
+ float temp2;
+ if (l < 0.5f)
+ temp2 = l * (1.0f + s);
else
temp2 = l + s - (l * s);
- const qreal temp1 = (qreal(2.0) * l) - temp2;
- qreal temp3[3] = { h + (qreal(1.0) / qreal(3.0)),
+ const float temp1 = (2.0f * l) - temp2;
+ float temp3[3] = { h + (1.0f / 3.0f),
h,
- h - (qreal(1.0) / qreal(3.0)) };
+ h - (1.0f / 3.0f) };
for (int i = 0; i != 3; ++i) {
- if (temp3[i] < qreal(0.0))
- temp3[i] += qreal(1.0);
- else if (temp3[i] > qreal(1.0))
- temp3[i] -= qreal(1.0);
+ if (temp3[i] < 0.0f)
+ temp3[i] += 1.0f;
+ else if (temp3[i] > 1.0f)
+ temp3[i] -= 1.0f;
- const qreal sixtemp3 = temp3[i] * qreal(6.0);
- if (sixtemp3 < qreal(1.0))
+ const float sixtemp3 = temp3[i] * 6.0f;
+ if (sixtemp3 < 1.0f)
color.ct.array[i+1] = qRound((temp1 + (temp2 - temp1) * sixtemp3) * USHRT_MAX);
- else if ((temp3[i] * qreal(2.0)) < qreal(1.0))
+ else if ((temp3[i] * 2.0f) < 1.0f)
color.ct.array[i+1] = qRound(temp2 * USHRT_MAX);
- else if ((temp3[i] * qreal(3.0)) < qreal(2.0))
- color.ct.array[i+1] = qRound((temp1 + (temp2 -temp1) * (qreal(2.0) /qreal(3.0) - temp3[i]) * qreal(6.0)) * USHRT_MAX);
+ else if ((temp3[i] * 3.0f) < 2.0f)
+ color.ct.array[i+1] = qRound((temp1 + (temp2 -temp1) * (2.0f /3.0f - temp3[i]) * 6.0f) * USHRT_MAX);
else
color.ct.array[i+1] = qRound(temp1 * USHRT_MAX);
}
@@ -2155,21 +2152,21 @@ QColor QColor::toRgb() const noexcept
}
case Cmyk:
{
- const qreal c = ct.acmyk.cyan / qreal(USHRT_MAX);
- const qreal m = ct.acmyk.magenta / qreal(USHRT_MAX);
- const qreal y = ct.acmyk.yellow / qreal(USHRT_MAX);
- const qreal k = ct.acmyk.black / qreal(USHRT_MAX);
-
- color.ct.argb.red = qRound((qreal(1.0) - (c * (qreal(1.0) - k) + k)) * USHRT_MAX);
- color.ct.argb.green = qRound((qreal(1.0) - (m * (qreal(1.0) - k) + k)) * USHRT_MAX);
- color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX);
+ const float c = ct.acmyk.cyan / float(USHRT_MAX);
+ const float m = ct.acmyk.magenta / float(USHRT_MAX);
+ const float y = ct.acmyk.yellow / float(USHRT_MAX);
+ const float k = ct.acmyk.black / float(USHRT_MAX);
+
+ color.ct.argb.red = qRound((1.0f - (c * (1.0f - k) + k)) * USHRT_MAX);
+ color.ct.argb.green = qRound((1.0f - (m * (1.0f - k) + k)) * USHRT_MAX);
+ color.ct.argb.blue = qRound((1.0f - (y * (1.0f - k) + k)) * USHRT_MAX);
break;
}
case ExtendedRgb:
- color.ct.argb.alpha = qRound(USHRT_MAX * qreal(castF16(ct.argbExtended.alphaF16)));
- color.ct.argb.red = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.redF16)), qreal(1.0)));
- color.ct.argb.green = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.greenF16)), qreal(1.0)));
- color.ct.argb.blue = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.blueF16)), qreal(1.0)));
+ color.ct.argb.alpha = qRound(USHRT_MAX * float(castF16(ct.argbExtended.alphaF16)));
+ color.ct.argb.red = qRound(USHRT_MAX * qBound(0.0f, float(castF16(ct.argbExtended.redF16)), 1.0f));
+ color.ct.argb.green = qRound(USHRT_MAX * qBound(0.0f, float(castF16(ct.argbExtended.greenF16)), 1.0f));
+ color.ct.argb.blue = qRound(USHRT_MAX * qBound(0.0f, float(castF16(ct.argbExtended.blueF16)), 1.0f));
break;
default:
break;
@@ -2201,12 +2198,12 @@ QColor QColor::toHsv() const noexcept
color.ct.ahsv.alpha = ct.argb.alpha;
color.ct.ahsv.pad = 0;
- const qreal r = ct.argb.red / qreal(USHRT_MAX);
- const qreal g = ct.argb.green / qreal(USHRT_MAX);
- const qreal b = ct.argb.blue / qreal(USHRT_MAX);
- const qreal max = Q_MAX_3(r, g, b);
- const qreal min = Q_MIN_3(r, g, b);
- const qreal delta = max - min;
+ const float r = ct.argb.red / float(USHRT_MAX);
+ const float g = ct.argb.green / float(USHRT_MAX);
+ const float b = ct.argb.blue / float(USHRT_MAX);
+ const float max = Q_MAX_3(r, g, b);
+ const float min = Q_MIN_3(r, g, b);
+ const float delta = max - min;
color.ct.ahsv.value = qRound(max * USHRT_MAX);
if (qFuzzyIsNull(delta)) {
// achromatic case, hue is undefined
@@ -2214,21 +2211,21 @@ QColor QColor::toHsv() const noexcept
color.ct.ahsv.saturation = 0;
} else {
// chromatic case
- qreal hue = 0;
+ float hue = 0;
color.ct.ahsv.saturation = qRound((delta / max) * USHRT_MAX);
if (qFuzzyCompare(r, max)) {
hue = ((g - b) /delta);
} else if (qFuzzyCompare(g, max)) {
- hue = (qreal(2.0) + (b - r) / delta);
+ hue = (2.0f + (b - r) / delta);
} else if (qFuzzyCompare(b, max)) {
- hue = (qreal(4.0) + (r - g) / delta);
+ hue = (4.0f + (r - g) / delta);
} else {
Q_ASSERT_X(false, "QColor::toHsv", "internal error");
}
- hue *= qreal(60.0);
- if (hue < qreal(0.0))
- hue += qreal(360.0);
- color.ct.ahsv.hue = qRound(hue * 100);
+ hue *= 60.0f;
+ if (hue < 0.0f)
+ hue += 360.0f;
+ color.ct.ahsv.hue = qRound(hue * 100.0f);
}
return color;
@@ -2252,14 +2249,14 @@ QColor QColor::toHsl() const noexcept
color.ct.ahsl.alpha = ct.argb.alpha;
color.ct.ahsl.pad = 0;
- const qreal r = ct.argb.red / qreal(USHRT_MAX);
- const qreal g = ct.argb.green / qreal(USHRT_MAX);
- const qreal b = ct.argb.blue / qreal(USHRT_MAX);
- const qreal max = Q_MAX_3(r, g, b);
- const qreal min = Q_MIN_3(r, g, b);
- const qreal delta = max - min;
- const qreal delta2 = max + min;
- const qreal lightness = qreal(0.5) * delta2;
+ const float r = ct.argb.red / float(USHRT_MAX);
+ const float g = ct.argb.green / float(USHRT_MAX);
+ const float b = ct.argb.blue / float(USHRT_MAX);
+ const float max = Q_MAX_3(r, g, b);
+ const float min = Q_MIN_3(r, g, b);
+ const float delta = max - min;
+ const float delta2 = max + min;
+ const float lightness = 0.5f * delta2;
color.ct.ahsl.lightness = qRound(lightness * USHRT_MAX);
if (qFuzzyIsNull(delta)) {
// achromatic case, hue is undefined
@@ -2267,24 +2264,24 @@ QColor QColor::toHsl() const noexcept
color.ct.ahsl.saturation = 0;
} else {
// chromatic case
- qreal hue = 0;
- if (lightness < qreal(0.5))
+ float hue = 0;
+ if (lightness < 0.5f)
color.ct.ahsl.saturation = qRound((delta / delta2) * USHRT_MAX);
else
- color.ct.ahsl.saturation = qRound((delta / (qreal(2.0) - delta2)) * USHRT_MAX);
+ color.ct.ahsl.saturation = qRound((delta / (2.0f - delta2)) * USHRT_MAX);
if (qFuzzyCompare(r, max)) {
hue = ((g - b) /delta);
} else if (qFuzzyCompare(g, max)) {
- hue = (qreal(2.0) + (b - r) / delta);
+ hue = (2.0f + (b - r) / delta);
} else if (qFuzzyCompare(b, max)) {
- hue = (qreal(4.0) + (r - g) / delta);
+ hue = (4.0f + (r - g) / delta);
} else {
Q_ASSERT_X(false, "QColor::toHsv", "internal error");
}
- hue *= qreal(60.0);
- if (hue < qreal(0.0))
- hue += qreal(360.0);
- color.ct.ahsl.hue = qRound(hue * 100);
+ hue *= 60.0f;
+ if (hue < 0.0f)
+ hue += 360.0f;
+ color.ct.ahsl.hue = qRound(hue * 100.0f);
}
return color;
@@ -2314,18 +2311,18 @@ QColor QColor::toCmyk() const noexcept
color.ct.acmyk.black = USHRT_MAX;
} else {
// rgb -> cmy
- const qreal r = ct.argb.red / qreal(USHRT_MAX);
- const qreal g = ct.argb.green / qreal(USHRT_MAX);
- const qreal b = ct.argb.blue / qreal(USHRT_MAX);
- qreal c = qreal(1.0) - r;
- qreal m = qreal(1.0) - g;
- qreal y = qreal(1.0) - b;
+ const float r = ct.argb.red / float(USHRT_MAX);
+ const float g = ct.argb.green / float(USHRT_MAX);
+ const float b = ct.argb.blue / float(USHRT_MAX);
+ float c = 1.0f - r;
+ float m = 1.0f - g;
+ float y = 1.0f - b;
// cmy -> cmyk
- const qreal k = qMin(c, qMin(m, y));
- c = (c - k) / (qreal(1.0) - k);
- m = (m - k) / (qreal(1.0) - k);
- y = (y - k) / (qreal(1.0) - k);
+ const float k = qMin(c, qMin(m, y));
+ c = (c - k) / (1.0f - k);
+ m = (m - k) / (1.0f - k);
+ y = (y - k) / (1.0f - k);
color.ct.acmyk.cyan = qRound(c * USHRT_MAX);
color.ct.acmyk.magenta = qRound(m * USHRT_MAX);
@@ -2427,16 +2424,16 @@ QColor QColor::fromRgb(int r, int g, int b, int a)
\sa fromRgb(), fromRgba64(), toRgb(), isValid()
*/
-QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a)
+QColor QColor::fromRgbF(float r, float g, float b, float a)
{
- if (a < qreal(0.0) || a > qreal(1.0)) {
+ if (a < 0.0f || a > 1.0f) {
qWarning("QColor::fromRgbF: Alpha parameter out of range");
return QColor();
}
- if (r < qreal(0.0) || r > qreal(1.0)
- || g < qreal(0.0) || g > qreal(1.0)
- || b < qreal(0.0) || b > qreal(1.0)) {
+ if (r < 0.0f || r > 1.0f
+ || g < 0.0f || g > 1.0f
+ || b < 0.0f || b > 1.0f) {
QColor color;
color.cspec = ExtendedRgb;
castF16(color.ct.argbExtended.alphaF16) = qfloat16(a);
@@ -2530,12 +2527,12 @@ QColor QColor::fromHsv(int h, int s, int v, int a)
\sa toHsv(), fromHsv(), isValid(), {QColor#The HSV Color Model}{The HSV Color Model}
*/
-QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a)
+QColor QColor::fromHsvF(float h, float s, float v, float a)
{
- if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0))
- || (s < qreal(0.0) || s > qreal(1.0))
- || (v < qreal(0.0) || v > qreal(1.0))
- || (a < qreal(0.0) || a > qreal(1.0))) {
+ if (((h < 0.0f || h > 1.0f) && h != -1.0f)
+ || (s < 0.0f || s > 1.0f)
+ || (v < 0.0f || v > 1.0f)
+ || (a < 0.0f || a > 1.0f)) {
qWarning("QColor::fromHsvF: HSV parameters out of range");
return QColor();
}
@@ -2543,7 +2540,7 @@ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a)
QColor color;
color.cspec = Hsv;
color.ct.ahsv.alpha = qRound(a * USHRT_MAX);
- color.ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000);
+ color.ct.ahsv.hue = h == -1.0f ? USHRT_MAX : qRound(h * 36000.0f);
color.ct.ahsv.saturation = qRound(s * USHRT_MAX);
color.ct.ahsv.value = qRound(v * USHRT_MAX);
color.ct.ahsv.pad = 0;
@@ -2594,12 +2591,12 @@ QColor QColor::fromHsl(int h, int s, int l, int a)
\sa toHsl(), fromHsl(), isValid(), {QColor#The HSL Color Model}{The HSL Color Model}
*/
-QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a)
+QColor QColor::fromHslF(float h, float s, float l, float a)
{
- if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0))
- || (s < qreal(0.0) || s > qreal(1.0))
- || (l < qreal(0.0) || l > qreal(1.0))
- || (a < qreal(0.0) || a > qreal(1.0))) {
+ if (((h < 0.0f || h > 1.0f) && h != -1.0f)
+ || (s < 0.0f || s > 1.0f)
+ || (l < 0.0f || l > 1.0f)
+ || (a < 0.0f || a > 1.0f)) {
qWarning("QColor::fromHslF: HSL parameters out of range");
return QColor();
}
@@ -2607,7 +2604,7 @@ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a)
QColor color;
color.cspec = Hsl;
color.ct.ahsl.alpha = qRound(a * USHRT_MAX);
- color.ct.ahsl.hue = (h == qreal(-1.0)) ? USHRT_MAX : qRound(h * 36000);
+ color.ct.ahsl.hue = (h == -1.0f) ? USHRT_MAX : qRound(h * 36000.0f);
if (color.ct.ahsl.hue == 36000)
color.ct.ahsl.hue = 0;
color.ct.ahsl.saturation = qRound(s * USHRT_MAX);
@@ -2655,7 +2652,7 @@ void QColor::getCmyk(int *c, int *m, int *y, int *k, int *a) const
\sa setCmykF(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-void QColor::getCmykF(qreal *c, qreal *m, qreal *y, qreal *k, qreal *a) const
+void QColor::getCmykF(float *c, float *m, float *y, float *k, float *a) const
{
if (!c || !m || !y || !k)
return;
@@ -2665,13 +2662,13 @@ void QColor::getCmykF(qreal *c, qreal *m, qreal *y, qreal *k, qreal *a) const
return;
}
- *c = ct.acmyk.cyan / qreal(USHRT_MAX);
- *m = ct.acmyk.magenta / qreal(USHRT_MAX);
- *y = ct.acmyk.yellow / qreal(USHRT_MAX);
- *k = ct.acmyk.black / qreal(USHRT_MAX);
+ *c = ct.acmyk.cyan / float(USHRT_MAX);
+ *m = ct.acmyk.magenta / float(USHRT_MAX);
+ *y = ct.acmyk.yellow / float(USHRT_MAX);
+ *k = ct.acmyk.black / float(USHRT_MAX);
if (a)
- *a = ct.acmyk.alpha / qreal(USHRT_MAX);
+ *a = ct.acmyk.alpha / float(USHRT_MAX);
}
/*!
@@ -2712,13 +2709,13 @@ void QColor::setCmyk(int c, int m, int y, int k, int a)
\sa getCmykF(), setCmyk(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-void QColor::setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
+void QColor::setCmykF(float c, float m, float y, float k, float a)
{
- if (c < qreal(0.0) || c > qreal(1.0)
- || m < qreal(0.0) || m > qreal(1.0)
- || y < qreal(0.0) || y > qreal(1.0)
- || k < qreal(0.0) || k > qreal(1.0)
- || a < qreal(0.0) || a > qreal(1.0)) {
+ if (c < 0.0f || c > 1.0f
+ || m < 0.0f || m > 1.0f
+ || y < 0.0f || y > 1.0f
+ || k < 0.0f || k > 1.0f
+ || a < 0.0f || a > 1.0f) {
qWarning("QColor::setCmykF: CMYK parameters out of range");
invalidate();
return;
@@ -2773,13 +2770,13 @@ QColor QColor::fromCmyk(int c, int m, int y, int k, int a)
\sa toCmyk(), fromCmyk(), isValid(), {QColor#The CMYK Color Model}{The CMYK Color Model}
*/
-QColor QColor::fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a)
+QColor QColor::fromCmykF(float c, float m, float y, float k, float a)
{
- if (c < qreal(0.0) || c > qreal(1.0)
- || m < qreal(0.0) || m > qreal(1.0)
- || y < qreal(0.0) || y > qreal(1.0)
- || k < qreal(0.0) || k > qreal(1.0)
- || a < qreal(0.0) || a > qreal(1.0)) {
+ if (c < 0.0f || c > 1.0f
+ || m < 0.0f || m > 1.0f
+ || y < 0.0f || y > 1.0f
+ || k < 0.0f || k > 1.0f
+ || a < 0.0f || a > 1.0f) {
qWarning("QColor::fromCmykF: CMYK parameters out of range");
return QColor();
}
@@ -2889,16 +2886,7 @@ QColor &QColor::operator=(Qt::GlobalColor color) noexcept
*/
bool QColor::operator==(const QColor &color) const noexcept
{
- if (cspec == Hsl && cspec == color.cspec) {
- return (ct.argb.alpha == color.ct.argb.alpha
- && ct.ahsl.hue % 36000 == color.ct.ahsl.hue % 36000
- && (qAbs(ct.ahsl.saturation - color.ct.ahsl.saturation) < 50
- || ct.ahsl.lightness == 0
- || color.ct.ahsl.lightness == 0
- || ct.ahsl.lightness == USHRT_MAX
- || color.ct.ahsl.lightness == USHRT_MAX)
- && (qAbs(ct.ahsl.lightness - color.ct.ahsl.lightness)) < 50);
- } else if ((cspec == ExtendedRgb || color.cspec == ExtendedRgb) &&
+ if ((cspec == ExtendedRgb || color.cspec == ExtendedRgb) &&
(cspec == color.cspec || cspec == Rgb || color.cspec == Rgb)) {
return qFuzzyCompare(alphaF(), color.alphaF())
&& qFuzzyCompare(redF(), color.redF())
@@ -2907,9 +2895,9 @@ bool QColor::operator==(const QColor &color) const noexcept
} else {
return (cspec == color.cspec
&& ct.argb.alpha == color.ct.argb.alpha
- && (((cspec == QColor::Hsv)
+ && (((cspec == QColor::Hsv || cspec == QColor::Hsl)
&& ((ct.ahsv.hue % 36000) == (color.ct.ahsv.hue % 36000)))
- || (ct.ahsv.hue == color.ct.ahsv.hue))
+ || (ct.argb.red == color.ct.argb.red))
&& ct.argb.green == color.ct.argb.green
&& ct.argb.blue == color.ct.argb.blue
&& ct.argb.pad == color.ct.argb.pad);
@@ -2933,7 +2921,7 @@ bool QColor::operator!=(const QColor &color) const noexcept
*/
QColor::operator QVariant() const
{
- return QVariant(QMetaType::QColor, this);
+ return QVariant::fromValue(*this);
}
/*! \internal
@@ -3139,7 +3127,7 @@ const uint qt_inv_premul_factor[256] = {
Returns the ARGB quadruplet (255, \a{r}, \a{g}, \a{b}).
- \sa qRgba(), qRed(), qGreen(), qBlue()
+ \sa qRgba(), qRed(), qGreen(), qBlue(), qAlpha()
*/
/*!
@@ -3148,7 +3136,7 @@ const uint qt_inv_premul_factor[256] = {
Returns the ARGB quadruplet (\a{a}, \a{r}, \a{g}, \a{b}).
- \sa qRgb(), qRed(), qGreen(), qBlue()
+ \sa qRgb(), qRed(), qGreen(), qBlue(), qAlpha()
*/
/*!
@@ -3211,7 +3199,11 @@ const uint qt_inv_premul_factor[256] = {
channel is \c ff, i.e opaque. For more information, see the
\l{QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing} section.
- \sa QColor::rgb(), QColor::rgba()
+ Here are some examples of how QRgb values can be created:
+
+ \snippet code/src_gui_painting_qcolor.cpp QRgb
+
+ \sa qRgb(), qRgba(), QColor::rgb(), QColor::rgba()
*/
/*!
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index 683826fbe7..2d6db1a14c 100644
--- a/src/gui/painting/qcolor.h
+++ b/src/gui/painting/qcolor.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLOR_H
#define QCOLOR_H
@@ -66,13 +30,15 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &);
class Q_GUI_EXPORT QColor
{
public:
+ // ### Qt7: make this "enum Spec: quint8 {...}" and reorder the members below for tighter
+ // struct packing. QColor could fit into the inline storage of a QVariant on 32bit.
enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl, ExtendedRgb };
enum NameFormat { HexRgb, HexArgb };
- Q_DECL_CONSTEXPR QColor() noexcept
+ constexpr QColor() noexcept
: cspec(Invalid), ct(USHRT_MAX, 0, 0, 0, 0) {}
QColor(Qt::GlobalColor color) noexcept;
- Q_DECL_CONSTEXPR QColor(int r, int g, int b, int a = 255) noexcept
+ constexpr QColor(int r, int g, int b, int a = 255) noexcept
: cspec(isRgbaValid(r, g, b, a) ? Rgb : Invalid),
ct(ushort(cspec == Rgb ? a * 0x0101 : 0),
ushort(cspec == Rgb ? r * 0x0101 : 0),
@@ -81,25 +47,28 @@ public:
0) {}
QColor(QRgb rgb) noexcept;
QColor(QRgba64 rgba64) noexcept;
-#if QT_STRINGVIEW_LEVEL < 2
inline QColor(const QString& name);
-#endif
explicit inline QColor(QStringView name);
- inline QColor(const char *aname) : QColor(QLatin1String(aname)) {}
- inline QColor(QLatin1String name);
+ inline QColor(const char *aname);
+ inline QColor(QLatin1StringView name);
QColor(Spec spec) noexcept;
+ static QColor fromString(QAnyStringView name) noexcept;
+
QColor &operator=(Qt::GlobalColor color) noexcept;
bool isValid() const noexcept;
QString name(NameFormat format = HexRgb) const;
-#if QT_STRINGVIEW_LEVEL < 2
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X_6_6("Use fromString() instead.")
void setNamedColor(const QString& name);
-#endif
+ QT_DEPRECATED_VERSION_X_6_6("Use fromString() instead.")
void setNamedColor(QStringView name);
- void setNamedColor(QLatin1String name);
+ QT_DEPRECATED_VERSION_X_6_6("Use fromString() instead.")
+ void setNamedColor(QLatin1StringView name);
+#endif
static QStringList colorNames();
@@ -109,8 +78,8 @@ public:
int alpha() const noexcept;
void setAlpha(int alpha);
- qreal alphaF() const noexcept;
- void setAlphaF(qreal alpha);
+ float alphaF() const noexcept;
+ void setAlphaF(float alpha);
int red() const noexcept;
int green() const noexcept;
@@ -119,18 +88,18 @@ public:
void setGreen(int green);
void setBlue(int blue);
- qreal redF() const noexcept;
- qreal greenF() const noexcept;
- qreal blueF() const noexcept;
- void setRedF(qreal red);
- void setGreenF(qreal green);
- void setBlueF(qreal blue);
+ float redF() const noexcept;
+ float greenF() const noexcept;
+ float blueF() const noexcept;
+ void setRedF(float red);
+ void setGreenF(float green);
+ void setBlueF(float blue);
void getRgb(int *r, int *g, int *b, int *a = nullptr) const;
void setRgb(int r, int g, int b, int a = 255);
- void getRgbF(qreal *r, qreal *g, qreal *b, qreal *a = nullptr) const;
- void setRgbF(qreal r, qreal g, qreal b, qreal a = 1.0);
+ void getRgbF(float *r, float *g, float *b, float *a = nullptr) const;
+ void setRgbF(float r, float g, float b, float a = 1.0);
QRgba64 rgba64() const noexcept;
void setRgba64(QRgba64 rgba) noexcept;
@@ -147,47 +116,47 @@ public:
int hsvSaturation() const noexcept;
int value() const noexcept;
- qreal hueF() const noexcept; // 0.0 <= hueF < 360.0
- qreal saturationF() const noexcept;
- qreal hsvHueF() const noexcept; // 0.0 <= hueF < 360.0
- qreal hsvSaturationF() const noexcept;
- qreal valueF() const noexcept;
+ float hueF() const noexcept; // 0.0 <= hueF < 360.0
+ float saturationF() const noexcept;
+ float hsvHueF() const noexcept; // 0.0 <= hueF < 360.0
+ float hsvSaturationF() const noexcept;
+ float valueF() const noexcept;
void getHsv(int *h, int *s, int *v, int *a = nullptr) const;
void setHsv(int h, int s, int v, int a = 255);
- void getHsvF(qreal *h, qreal *s, qreal *v, qreal *a = nullptr) const;
- void setHsvF(qreal h, qreal s, qreal v, qreal a = 1.0);
+ void getHsvF(float *h, float *s, float *v, float *a = nullptr) const;
+ void setHsvF(float h, float s, float v, float a = 1.0);
int cyan() const noexcept;
int magenta() const noexcept;
int yellow() const noexcept;
int black() const noexcept;
- qreal cyanF() const noexcept;
- qreal magentaF() const noexcept;
- qreal yellowF() const noexcept;
- qreal blackF() const noexcept;
+ float cyanF() const noexcept;
+ float magentaF() const noexcept;
+ float yellowF() const noexcept;
+ float blackF() const noexcept;
void getCmyk(int *c, int *m, int *y, int *k, int *a = nullptr) const;
void setCmyk(int c, int m, int y, int k, int a = 255);
- void getCmykF(qreal *c, qreal *m, qreal *y, qreal *k, qreal *a = nullptr) const;
- void setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0);
+ void getCmykF(float *c, float *m, float *y, float *k, float *a = nullptr) const;
+ void setCmykF(float c, float m, float y, float k, float a = 1.0);
int hslHue() const noexcept; // 0 <= hue < 360
int hslSaturation() const noexcept;
int lightness() const noexcept;
- qreal hslHueF() const noexcept; // 0.0 <= hueF < 360.0
- qreal hslSaturationF() const noexcept;
- qreal lightnessF() const noexcept;
+ float hslHueF() const noexcept; // 0.0 <= hueF < 360.0
+ float hslSaturationF() const noexcept;
+ float lightnessF() const noexcept;
void getHsl(int *h, int *s, int *l, int *a = nullptr) const;
void setHsl(int h, int s, int l, int a = 255);
- void getHslF(qreal *h, qreal *s, qreal *l, qreal *a = nullptr) const;
- void setHslF(qreal h, qreal s, qreal l, qreal a = 1.0);
+ void getHslF(float *h, float *s, float *l, float *a = nullptr) const;
+ void setHslF(float h, float s, float l, float a = 1.0);
QColor toRgb() const noexcept;
QColor toHsv() const noexcept;
@@ -195,47 +164,49 @@ public:
QColor toHsl() const noexcept;
QColor toExtendedRgb() const noexcept;
- Q_REQUIRED_RESULT QColor convertTo(Spec colorSpec) const noexcept;
+ [[nodiscard]] QColor convertTo(Spec colorSpec) const noexcept;
static QColor fromRgb(QRgb rgb) noexcept;
static QColor fromRgba(QRgb rgba) noexcept;
static QColor fromRgb(int r, int g, int b, int a = 255);
- static QColor fromRgbF(qreal r, qreal g, qreal b, qreal a = 1.0);
+ static QColor fromRgbF(float r, float g, float b, float a = 1.0);
static QColor fromRgba64(ushort r, ushort g, ushort b, ushort a = USHRT_MAX) noexcept;
static QColor fromRgba64(QRgba64 rgba) noexcept;
static QColor fromHsv(int h, int s, int v, int a = 255);
- static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0);
+ static QColor fromHsvF(float h, float s, float v, float a = 1.0);
static QColor fromCmyk(int c, int m, int y, int k, int a = 255);
- static QColor fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a = 1.0);
+ static QColor fromCmykF(float c, float m, float y, float k, float a = 1.0);
static QColor fromHsl(int h, int s, int l, int a = 255);
- static QColor fromHslF(qreal h, qreal s, qreal l, qreal a = 1.0);
+ static QColor fromHslF(float h, float s, float l, float a = 1.0);
- Q_REQUIRED_RESULT QColor lighter(int f = 150) const noexcept;
- Q_REQUIRED_RESULT QColor darker(int f = 200) const noexcept;
+ [[nodiscard]] QColor lighter(int f = 150) const noexcept;
+ [[nodiscard]] QColor darker(int f = 200) const noexcept;
bool operator==(const QColor &c) const noexcept;
bool operator!=(const QColor &c) const noexcept;
operator QVariant() const;
-#if QT_STRINGVIEW_LEVEL < 2
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X_6_6("Use isValidColorName() instead.")
static bool isValidColor(const QString &name);
-#endif
+ QT_DEPRECATED_VERSION_X_6_6("Use isValidColorName() instead.")
static bool isValidColor(QStringView) noexcept;
- static bool isValidColor(QLatin1String) noexcept;
+ QT_DEPRECATED_VERSION_X_6_6("Use isValidColorName() instead.")
+ static bool isValidColor(QLatin1StringView) noexcept;
+#endif
+ static bool isValidColorName(QAnyStringView) noexcept;
private:
void invalidate() noexcept;
- template <typename String>
- bool setColorFromString(String name);
- static Q_DECL_CONSTEXPR bool isRgbaValid(int r, int g, int b, int a = 255) noexcept Q_DECL_CONST_FUNCTION
+ static constexpr bool isRgbaValid(int r, int g, int b, int a = 255) noexcept Q_DECL_CONST_FUNCTION
{
return uint(r) <= 255 && uint(g) <= 255 && uint(b) <= 255 && uint(a) <= 255;
}
@@ -244,7 +215,7 @@ private:
union CT {
#ifdef Q_COMPILER_UNIFORM_INIT
CT() {} // doesn't init anything, thus can't be constexpr
- Q_DECL_CONSTEXPR explicit CT(ushort a1, ushort a2, ushort a3, ushort a4, ushort a5) noexcept
+ constexpr explicit CT(ushort a1, ushort a2, ushort a3, ushort a4, ushort a5) noexcept
: array{a1, a2, a3, a4, a5} {}
#endif
struct {
@@ -293,205 +264,201 @@ private:
#ifdef Q_COMPILER_UNIFORM_INIT
public: // can't give friendship to a namespace, so it needs to be public
- Q_DECL_CONSTEXPR explicit QColor(Spec spec, ushort a1, ushort a2, ushort a3, ushort a4, ushort a5=0) noexcept
+ constexpr explicit QColor(Spec spec, ushort a1, ushort a2, ushort a3, ushort a4, ushort a5=0) noexcept
: cspec(spec), ct(a1, a2, a3, a4, a5) {}
#endif // Q_COMPILER_UNIFORM_INIT
};
-Q_DECLARE_TYPEINFO(QColor, QT_VERSION >= QT_VERSION_CHECK(6,0,0) ? Q_MOVABLE_TYPE : Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QColor, Q_RELOCATABLE_TYPE);
-inline QColor::QColor(QLatin1String aname)
-{ setNamedColor(aname); }
+inline QColor::QColor(QLatin1StringView aname)
+ : QColor(fromString(aname)) {}
inline QColor::QColor(QStringView aname)
-{ setNamedColor(aname); }
+ : QColor(fromString(aname)) {}
-#if QT_STRINGVIEW_LEVEL < 2
inline QColor::QColor(const QString& aname)
-{ setNamedColor(aname); }
-#endif
+ : QColor(fromString(aname)) {}
+
+inline QColor::QColor(const char *aname)
+ : QColor(fromString(aname)) {}
inline bool QColor::isValid() const noexcept
{ return cspec != Invalid; }
-// define these namespaces even if the contents are ifdef'd out
namespace QColorConstants
{
-namespace Svg {}
-
-#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT)
// Qt::GlobalColor names
- constexpr Q_DECL_UNUSED QColor Color0 {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor Color1 {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor Black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor White {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkGray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor Gray {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0xa0 * 0x101, 0xa4 * 0x101};
- constexpr Q_DECL_UNUSED QColor LightGray {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
- constexpr Q_DECL_UNUSED QColor Red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor Green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor Blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor Cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor Magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor Yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkRed {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkGreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkBlue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkCyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkMagenta {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor DarkYellow {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor Transparent {QColor::Rgb, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor Color0 {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor Color1 {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor Black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor White {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor DarkGray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor Gray {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0xa0 * 0x101, 0xa4 * 0x101};
+ constexpr inline QColor LightGray {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
+ constexpr inline QColor Red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor Green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr inline QColor Blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr inline QColor Cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor Magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr inline QColor Yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr inline QColor DarkRed {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor DarkGreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor DarkBlue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor DarkCyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor DarkMagenta {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor DarkYellow {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor Transparent {QColor::Rgb, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
// SVG names supported by QColor (see qcolor.cpp).
namespace Svg {
- constexpr Q_DECL_UNUSED QColor aliceblue {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor antiquewhite {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xeb * 0x101, 0xd7 * 0x101};
- constexpr Q_DECL_UNUSED QColor aqua {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor aquamarine {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0xd4 * 0x101};
- constexpr Q_DECL_UNUSED QColor azure {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor beige {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xdc * 0x101};
- constexpr Q_DECL_UNUSED QColor bisque {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xc4 * 0x101};
- constexpr Q_DECL_UNUSED QColor black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor blanchedalmond {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xeb * 0x101, 0xcd * 0x101};
- constexpr Q_DECL_UNUSED QColor blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor blueviolet {QColor::Rgb, 0xff * 0x101, 0x8a * 0x101, 0x2b * 0x101, 0xe2 * 0x101};
- constexpr Q_DECL_UNUSED QColor brown {QColor::Rgb, 0xff * 0x101, 0xa5 * 0x101, 0x2a * 0x101, 0x2a * 0x101};
- constexpr Q_DECL_UNUSED QColor burlywood {QColor::Rgb, 0xff * 0x101, 0xde * 0x101, 0xb8 * 0x101, 0x87 * 0x101};
- constexpr Q_DECL_UNUSED QColor cadetblue {QColor::Rgb, 0xff * 0x101, 0x5f * 0x101, 0x9e * 0x101, 0xa0 * 0x101};
- constexpr Q_DECL_UNUSED QColor chartreuse {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor chocolate {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0x69 * 0x101, 0x1e * 0x101};
- constexpr Q_DECL_UNUSED QColor coral {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x7f * 0x101, 0x50 * 0x101};
- constexpr Q_DECL_UNUSED QColor cornflowerblue {QColor::Rgb, 0xff * 0x101, 0x64 * 0x101, 0x95 * 0x101, 0xed * 0x101};
- constexpr Q_DECL_UNUSED QColor cornsilk {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf8 * 0x101, 0xdc * 0x101};
- constexpr Q_DECL_UNUSED QColor crimson {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0x14 * 0x101, 0x3c * 0x101};
- constexpr Q_DECL_UNUSED QColor cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor darkblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x8b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkcyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x8b * 0x101, 0x8b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkgoldenrod {QColor::Rgb, 0xff * 0x101, 0xb8 * 0x101, 0x86 * 0x101, 0x0b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkgray {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
- constexpr Q_DECL_UNUSED QColor darkgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x64 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor darkgrey {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
- constexpr Q_DECL_UNUSED QColor darkkhaki {QColor::Rgb, 0xff * 0x101, 0xbd * 0x101, 0xb7 * 0x101, 0x6b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkmagenta {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x8b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkolivegreen {QColor::Rgb, 0xff * 0x101, 0x55 * 0x101, 0x6b * 0x101, 0x2f * 0x101};
- constexpr Q_DECL_UNUSED QColor darkorange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x8c * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor darkorchid {QColor::Rgb, 0xff * 0x101, 0x99 * 0x101, 0x32 * 0x101, 0xcc * 0x101};
- constexpr Q_DECL_UNUSED QColor darkred {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor darksalmon {QColor::Rgb, 0xff * 0x101, 0xe9 * 0x101, 0x96 * 0x101, 0x7a * 0x101};
- constexpr Q_DECL_UNUSED QColor darkseagreen {QColor::Rgb, 0xff * 0x101, 0x8f * 0x101, 0xbc * 0x101, 0x8f * 0x101};
- constexpr Q_DECL_UNUSED QColor darkslateblue {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0x3d * 0x101, 0x8b * 0x101};
- constexpr Q_DECL_UNUSED QColor darkslategray {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
- constexpr Q_DECL_UNUSED QColor darkslategrey {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
- constexpr Q_DECL_UNUSED QColor darkturquoise {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xce * 0x101, 0xd1 * 0x101};
- constexpr Q_DECL_UNUSED QColor darkviolet {QColor::Rgb, 0xff * 0x101, 0x94 * 0x101, 0x00 * 0x101, 0xd3 * 0x101};
- constexpr Q_DECL_UNUSED QColor deeppink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x14 * 0x101, 0x93 * 0x101};
- constexpr Q_DECL_UNUSED QColor deepskyblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xbf * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor dimgray {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
- constexpr Q_DECL_UNUSED QColor dimgrey {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
- constexpr Q_DECL_UNUSED QColor dodgerblue {QColor::Rgb, 0xff * 0x101, 0x1e * 0x101, 0x90 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor firebrick {QColor::Rgb, 0xff * 0x101, 0xb2 * 0x101, 0x22 * 0x101, 0x22 * 0x101};
- constexpr Q_DECL_UNUSED QColor floralwhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101};
- constexpr Q_DECL_UNUSED QColor forestgreen {QColor::Rgb, 0xff * 0x101, 0x22 * 0x101, 0x8b * 0x101, 0x22 * 0x101};
- constexpr Q_DECL_UNUSED QColor fuchsia {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor gainsboro {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0xdc * 0x101, 0xdc * 0x101};
- constexpr Q_DECL_UNUSED QColor ghostwhite {QColor::Rgb, 0xff * 0x101, 0xf8 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor gold {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xd7 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor goldenrod {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0xa5 * 0x101, 0x20 * 0x101};
- constexpr Q_DECL_UNUSED QColor gray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor greenyellow {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xff * 0x101, 0x2f * 0x101};
- constexpr Q_DECL_UNUSED QColor grey {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor honeydew {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xf0 * 0x101};
- constexpr Q_DECL_UNUSED QColor hotpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x69 * 0x101, 0xb4 * 0x101};
- constexpr Q_DECL_UNUSED QColor indianred {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x5c * 0x101, 0x5c * 0x101};
- constexpr Q_DECL_UNUSED QColor indigo {QColor::Rgb, 0xff * 0x101, 0x4b * 0x101, 0x00 * 0x101, 0x82 * 0x101};
- constexpr Q_DECL_UNUSED QColor ivory {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101};
- constexpr Q_DECL_UNUSED QColor khaki {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xe6 * 0x101, 0x8c * 0x101};
- constexpr Q_DECL_UNUSED QColor lavender {QColor::Rgb, 0xff * 0x101, 0xe6 * 0x101, 0xe6 * 0x101, 0xfa * 0x101};
- constexpr Q_DECL_UNUSED QColor lavenderblush {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101, 0xf5 * 0x101};
- constexpr Q_DECL_UNUSED QColor lawngreen {QColor::Rgb, 0xff * 0x101, 0x7c * 0x101, 0xfc * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor lemonchiffon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xcd * 0x101};
- constexpr Q_DECL_UNUSED QColor lightblue {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xd8 * 0x101, 0xe6 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightcoral {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightcyan {QColor::Rgb, 0xff * 0x101, 0xe0 * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor lightgoldenrodyellow {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101, 0xd2 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightgray {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightgreen {QColor::Rgb, 0xff * 0x101, 0x90 * 0x101, 0xee * 0x101, 0x90 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightgrey {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xb6 * 0x101, 0xc1 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightsalmon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa0 * 0x101, 0x7a * 0x101};
- constexpr Q_DECL_UNUSED QColor lightseagreen {QColor::Rgb, 0xff * 0x101, 0x20 * 0x101, 0xb2 * 0x101, 0xaa * 0x101};
- constexpr Q_DECL_UNUSED QColor lightskyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xfa * 0x101};
- constexpr Q_DECL_UNUSED QColor lightslategray {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightslategrey {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
- constexpr Q_DECL_UNUSED QColor lightsteelblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xc4 * 0x101, 0xde * 0x101};
- constexpr Q_DECL_UNUSED QColor lightyellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xe0 * 0x101};
- constexpr Q_DECL_UNUSED QColor lime {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor limegreen {QColor::Rgb, 0xff * 0x101, 0x32 * 0x101, 0xcd * 0x101, 0x32 * 0x101};
- constexpr Q_DECL_UNUSED QColor linen {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101, 0xe6 * 0x101};
- constexpr Q_DECL_UNUSED QColor magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor maroon {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumaquamarine {QColor::Rgb, 0xff * 0x101, 0x66 * 0x101, 0xcd * 0x101, 0xaa * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xcd * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumorchid {QColor::Rgb, 0xff * 0x101, 0xba * 0x101, 0x55 * 0x101, 0xd3 * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumpurple {QColor::Rgb, 0xff * 0x101, 0x93 * 0x101, 0x70 * 0x101, 0xdb * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumseagreen {QColor::Rgb, 0xff * 0x101, 0x3c * 0x101, 0xb3 * 0x101, 0x71 * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumslateblue {QColor::Rgb, 0xff * 0x101, 0x7b * 0x101, 0x68 * 0x101, 0xee * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumspringgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xfa * 0x101, 0x9a * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumturquoise {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0xd1 * 0x101, 0xcc * 0x101};
- constexpr Q_DECL_UNUSED QColor mediumvioletred {QColor::Rgb, 0xff * 0x101, 0xc7 * 0x101, 0x15 * 0x101, 0x85 * 0x101};
- constexpr Q_DECL_UNUSED QColor midnightblue {QColor::Rgb, 0xff * 0x101, 0x19 * 0x101, 0x19 * 0x101, 0x70 * 0x101};
- constexpr Q_DECL_UNUSED QColor mintcream {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xff * 0x101, 0xfa * 0x101};
- constexpr Q_DECL_UNUSED QColor mistyrose {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xe1 * 0x101};
- constexpr Q_DECL_UNUSED QColor moccasin {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xb5 * 0x101};
- constexpr Q_DECL_UNUSED QColor navajowhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xde * 0x101, 0xad * 0x101};
- constexpr Q_DECL_UNUSED QColor navy {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor oldlace {QColor::Rgb, 0xff * 0x101, 0xfd * 0x101, 0xf5 * 0x101, 0xe6 * 0x101};
- constexpr Q_DECL_UNUSED QColor olive {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor olivedrab {QColor::Rgb, 0xff * 0x101, 0x6b * 0x101, 0x8e * 0x101, 0x23 * 0x101};
- constexpr Q_DECL_UNUSED QColor orange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa5 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor orangered {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x45 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor orchid {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0x70 * 0x101, 0xd6 * 0x101};
- constexpr Q_DECL_UNUSED QColor palegoldenrod {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0xe8 * 0x101, 0xaa * 0x101};
- constexpr Q_DECL_UNUSED QColor palegreen {QColor::Rgb, 0xff * 0x101, 0x98 * 0x101, 0xfb * 0x101, 0x98 * 0x101};
- constexpr Q_DECL_UNUSED QColor paleturquoise {QColor::Rgb, 0xff * 0x101, 0xaf * 0x101, 0xee * 0x101, 0xee * 0x101};
- constexpr Q_DECL_UNUSED QColor palevioletred {QColor::Rgb, 0xff * 0x101, 0xdb * 0x101, 0x70 * 0x101, 0x93 * 0x101};
- constexpr Q_DECL_UNUSED QColor papayawhip {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xef * 0x101, 0xd5 * 0x101};
- constexpr Q_DECL_UNUSED QColor peachpuff {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xda * 0x101, 0xb9 * 0x101};
- constexpr Q_DECL_UNUSED QColor peru {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x85 * 0x101, 0x3f * 0x101};
- constexpr Q_DECL_UNUSED QColor pink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xc0 * 0x101, 0xcb * 0x101};
- constexpr Q_DECL_UNUSED QColor plum {QColor::Rgb, 0xff * 0x101, 0xdd * 0x101, 0xa0 * 0x101, 0xdd * 0x101};
- constexpr Q_DECL_UNUSED QColor powderblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xe0 * 0x101, 0xe6 * 0x101};
- constexpr Q_DECL_UNUSED QColor purple {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor rosybrown {QColor::Rgb, 0xff * 0x101, 0xbc * 0x101, 0x8f * 0x101, 0x8f * 0x101};
- constexpr Q_DECL_UNUSED QColor royalblue {QColor::Rgb, 0xff * 0x101, 0x41 * 0x101, 0x69 * 0x101, 0xe1 * 0x101};
- constexpr Q_DECL_UNUSED QColor saddlebrown {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x45 * 0x101, 0x13 * 0x101};
- constexpr Q_DECL_UNUSED QColor salmon {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0x80 * 0x101, 0x72 * 0x101};
- constexpr Q_DECL_UNUSED QColor sandybrown {QColor::Rgb, 0xff * 0x101, 0xf4 * 0x101, 0xa4 * 0x101, 0x60 * 0x101};
- constexpr Q_DECL_UNUSED QColor seagreen {QColor::Rgb, 0xff * 0x101, 0x2e * 0x101, 0x8b * 0x101, 0x57 * 0x101};
- constexpr Q_DECL_UNUSED QColor seashell {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf5 * 0x101, 0xee * 0x101};
- constexpr Q_DECL_UNUSED QColor sienna {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0x52 * 0x101, 0x2d * 0x101};
- constexpr Q_DECL_UNUSED QColor silver {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
- constexpr Q_DECL_UNUSED QColor skyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xeb * 0x101};
- constexpr Q_DECL_UNUSED QColor slateblue {QColor::Rgb, 0xff * 0x101, 0x6a * 0x101, 0x5a * 0x101, 0xcd * 0x101};
- constexpr Q_DECL_UNUSED QColor slategray {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
- constexpr Q_DECL_UNUSED QColor slategrey {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
- constexpr Q_DECL_UNUSED QColor snow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101};
- constexpr Q_DECL_UNUSED QColor springgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x7f * 0x101};
- constexpr Q_DECL_UNUSED QColor steelblue {QColor::Rgb, 0xff * 0x101, 0x46 * 0x101, 0x82 * 0x101, 0xb4 * 0x101};
- constexpr Q_DECL_UNUSED QColor tan {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0xb4 * 0x101, 0x8c * 0x101};
- constexpr Q_DECL_UNUSED QColor teal {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
- constexpr Q_DECL_UNUSED QColor thistle {QColor::Rgb, 0xff * 0x101, 0xd8 * 0x101, 0xbf * 0x101, 0xd8 * 0x101};
- constexpr Q_DECL_UNUSED QColor tomato {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x63 * 0x101, 0x47 * 0x101};
- constexpr Q_DECL_UNUSED QColor turquoise {QColor::Rgb, 0xff * 0x101, 0x40 * 0x101, 0xe0 * 0x101, 0xd0 * 0x101};
- constexpr Q_DECL_UNUSED QColor violet {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0x82 * 0x101, 0xee * 0x101};
- constexpr Q_DECL_UNUSED QColor wheat {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xde * 0x101, 0xb3 * 0x101};
- constexpr Q_DECL_UNUSED QColor white {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
- constexpr Q_DECL_UNUSED QColor whitesmoke {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xf5 * 0x101};
- constexpr Q_DECL_UNUSED QColor yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
- constexpr Q_DECL_UNUSED QColor yellowgreen {QColor::Rgb, 0xff * 0x101, 0x9a * 0x101, 0xcd * 0x101, 0x32 * 0x101};
+ constexpr inline QColor aliceblue {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
+ constexpr inline QColor antiquewhite {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xeb * 0x101, 0xd7 * 0x101};
+ constexpr inline QColor aqua {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor aquamarine {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0xd4 * 0x101};
+ constexpr inline QColor azure {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor beige {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xdc * 0x101};
+ constexpr inline QColor bisque {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xc4 * 0x101};
+ constexpr inline QColor black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor blanchedalmond {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xeb * 0x101, 0xcd * 0x101};
+ constexpr inline QColor blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr inline QColor blueviolet {QColor::Rgb, 0xff * 0x101, 0x8a * 0x101, 0x2b * 0x101, 0xe2 * 0x101};
+ constexpr inline QColor brown {QColor::Rgb, 0xff * 0x101, 0xa5 * 0x101, 0x2a * 0x101, 0x2a * 0x101};
+ constexpr inline QColor burlywood {QColor::Rgb, 0xff * 0x101, 0xde * 0x101, 0xb8 * 0x101, 0x87 * 0x101};
+ constexpr inline QColor cadetblue {QColor::Rgb, 0xff * 0x101, 0x5f * 0x101, 0x9e * 0x101, 0xa0 * 0x101};
+ constexpr inline QColor chartreuse {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr inline QColor chocolate {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0x69 * 0x101, 0x1e * 0x101};
+ constexpr inline QColor coral {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x7f * 0x101, 0x50 * 0x101};
+ constexpr inline QColor cornflowerblue {QColor::Rgb, 0xff * 0x101, 0x64 * 0x101, 0x95 * 0x101, 0xed * 0x101};
+ constexpr inline QColor cornsilk {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf8 * 0x101, 0xdc * 0x101};
+ constexpr inline QColor crimson {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0x14 * 0x101, 0x3c * 0x101};
+ constexpr inline QColor cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor darkblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x8b * 0x101};
+ constexpr inline QColor darkcyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x8b * 0x101, 0x8b * 0x101};
+ constexpr inline QColor darkgoldenrod {QColor::Rgb, 0xff * 0x101, 0xb8 * 0x101, 0x86 * 0x101, 0x0b * 0x101};
+ constexpr inline QColor darkgray {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
+ constexpr inline QColor darkgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x64 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor darkgrey {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
+ constexpr inline QColor darkkhaki {QColor::Rgb, 0xff * 0x101, 0xbd * 0x101, 0xb7 * 0x101, 0x6b * 0x101};
+ constexpr inline QColor darkmagenta {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x8b * 0x101};
+ constexpr inline QColor darkolivegreen {QColor::Rgb, 0xff * 0x101, 0x55 * 0x101, 0x6b * 0x101, 0x2f * 0x101};
+ constexpr inline QColor darkorange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x8c * 0x101, 0x00 * 0x101};
+ constexpr inline QColor darkorchid {QColor::Rgb, 0xff * 0x101, 0x99 * 0x101, 0x32 * 0x101, 0xcc * 0x101};
+ constexpr inline QColor darkred {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor darksalmon {QColor::Rgb, 0xff * 0x101, 0xe9 * 0x101, 0x96 * 0x101, 0x7a * 0x101};
+ constexpr inline QColor darkseagreen {QColor::Rgb, 0xff * 0x101, 0x8f * 0x101, 0xbc * 0x101, 0x8f * 0x101};
+ constexpr inline QColor darkslateblue {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0x3d * 0x101, 0x8b * 0x101};
+ constexpr inline QColor darkslategray {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
+ constexpr inline QColor darkslategrey {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
+ constexpr inline QColor darkturquoise {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xce * 0x101, 0xd1 * 0x101};
+ constexpr inline QColor darkviolet {QColor::Rgb, 0xff * 0x101, 0x94 * 0x101, 0x00 * 0x101, 0xd3 * 0x101};
+ constexpr inline QColor deeppink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x14 * 0x101, 0x93 * 0x101};
+ constexpr inline QColor deepskyblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xbf * 0x101, 0xff * 0x101};
+ constexpr inline QColor dimgray {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
+ constexpr inline QColor dimgrey {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
+ constexpr inline QColor dodgerblue {QColor::Rgb, 0xff * 0x101, 0x1e * 0x101, 0x90 * 0x101, 0xff * 0x101};
+ constexpr inline QColor firebrick {QColor::Rgb, 0xff * 0x101, 0xb2 * 0x101, 0x22 * 0x101, 0x22 * 0x101};
+ constexpr inline QColor floralwhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101};
+ constexpr inline QColor forestgreen {QColor::Rgb, 0xff * 0x101, 0x22 * 0x101, 0x8b * 0x101, 0x22 * 0x101};
+ constexpr inline QColor fuchsia {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr inline QColor gainsboro {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0xdc * 0x101, 0xdc * 0x101};
+ constexpr inline QColor ghostwhite {QColor::Rgb, 0xff * 0x101, 0xf8 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
+ constexpr inline QColor gold {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xd7 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor goldenrod {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0xa5 * 0x101, 0x20 * 0x101};
+ constexpr inline QColor gray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor greenyellow {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xff * 0x101, 0x2f * 0x101};
+ constexpr inline QColor grey {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor honeydew {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xf0 * 0x101};
+ constexpr inline QColor hotpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x69 * 0x101, 0xb4 * 0x101};
+ constexpr inline QColor indianred {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x5c * 0x101, 0x5c * 0x101};
+ constexpr inline QColor indigo {QColor::Rgb, 0xff * 0x101, 0x4b * 0x101, 0x00 * 0x101, 0x82 * 0x101};
+ constexpr inline QColor ivory {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101};
+ constexpr inline QColor khaki {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xe6 * 0x101, 0x8c * 0x101};
+ constexpr inline QColor lavender {QColor::Rgb, 0xff * 0x101, 0xe6 * 0x101, 0xe6 * 0x101, 0xfa * 0x101};
+ constexpr inline QColor lavenderblush {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101, 0xf5 * 0x101};
+ constexpr inline QColor lawngreen {QColor::Rgb, 0xff * 0x101, 0x7c * 0x101, 0xfc * 0x101, 0x00 * 0x101};
+ constexpr inline QColor lemonchiffon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xcd * 0x101};
+ constexpr inline QColor lightblue {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xd8 * 0x101, 0xe6 * 0x101};
+ constexpr inline QColor lightcoral {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor lightcyan {QColor::Rgb, 0xff * 0x101, 0xe0 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor lightgoldenrodyellow {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101, 0xd2 * 0x101};
+ constexpr inline QColor lightgray {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
+ constexpr inline QColor lightgreen {QColor::Rgb, 0xff * 0x101, 0x90 * 0x101, 0xee * 0x101, 0x90 * 0x101};
+ constexpr inline QColor lightgrey {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
+ constexpr inline QColor lightpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xb6 * 0x101, 0xc1 * 0x101};
+ constexpr inline QColor lightsalmon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa0 * 0x101, 0x7a * 0x101};
+ constexpr inline QColor lightseagreen {QColor::Rgb, 0xff * 0x101, 0x20 * 0x101, 0xb2 * 0x101, 0xaa * 0x101};
+ constexpr inline QColor lightskyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xfa * 0x101};
+ constexpr inline QColor lightslategray {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
+ constexpr inline QColor lightslategrey {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
+ constexpr inline QColor lightsteelblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xc4 * 0x101, 0xde * 0x101};
+ constexpr inline QColor lightyellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xe0 * 0x101};
+ constexpr inline QColor lime {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr inline QColor limegreen {QColor::Rgb, 0xff * 0x101, 0x32 * 0x101, 0xcd * 0x101, 0x32 * 0x101};
+ constexpr inline QColor linen {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101, 0xe6 * 0x101};
+ constexpr inline QColor magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr inline QColor maroon {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor mediumaquamarine {QColor::Rgb, 0xff * 0x101, 0x66 * 0x101, 0xcd * 0x101, 0xaa * 0x101};
+ constexpr inline QColor mediumblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xcd * 0x101};
+ constexpr inline QColor mediumorchid {QColor::Rgb, 0xff * 0x101, 0xba * 0x101, 0x55 * 0x101, 0xd3 * 0x101};
+ constexpr inline QColor mediumpurple {QColor::Rgb, 0xff * 0x101, 0x93 * 0x101, 0x70 * 0x101, 0xdb * 0x101};
+ constexpr inline QColor mediumseagreen {QColor::Rgb, 0xff * 0x101, 0x3c * 0x101, 0xb3 * 0x101, 0x71 * 0x101};
+ constexpr inline QColor mediumslateblue {QColor::Rgb, 0xff * 0x101, 0x7b * 0x101, 0x68 * 0x101, 0xee * 0x101};
+ constexpr inline QColor mediumspringgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xfa * 0x101, 0x9a * 0x101};
+ constexpr inline QColor mediumturquoise {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0xd1 * 0x101, 0xcc * 0x101};
+ constexpr inline QColor mediumvioletred {QColor::Rgb, 0xff * 0x101, 0xc7 * 0x101, 0x15 * 0x101, 0x85 * 0x101};
+ constexpr inline QColor midnightblue {QColor::Rgb, 0xff * 0x101, 0x19 * 0x101, 0x19 * 0x101, 0x70 * 0x101};
+ constexpr inline QColor mintcream {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xff * 0x101, 0xfa * 0x101};
+ constexpr inline QColor mistyrose {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xe1 * 0x101};
+ constexpr inline QColor moccasin {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xb5 * 0x101};
+ constexpr inline QColor navajowhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xde * 0x101, 0xad * 0x101};
+ constexpr inline QColor navy {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor oldlace {QColor::Rgb, 0xff * 0x101, 0xfd * 0x101, 0xf5 * 0x101, 0xe6 * 0x101};
+ constexpr inline QColor olive {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor olivedrab {QColor::Rgb, 0xff * 0x101, 0x6b * 0x101, 0x8e * 0x101, 0x23 * 0x101};
+ constexpr inline QColor orange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa5 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor orangered {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x45 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor orchid {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0x70 * 0x101, 0xd6 * 0x101};
+ constexpr inline QColor palegoldenrod {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0xe8 * 0x101, 0xaa * 0x101};
+ constexpr inline QColor palegreen {QColor::Rgb, 0xff * 0x101, 0x98 * 0x101, 0xfb * 0x101, 0x98 * 0x101};
+ constexpr inline QColor paleturquoise {QColor::Rgb, 0xff * 0x101, 0xaf * 0x101, 0xee * 0x101, 0xee * 0x101};
+ constexpr inline QColor palevioletred {QColor::Rgb, 0xff * 0x101, 0xdb * 0x101, 0x70 * 0x101, 0x93 * 0x101};
+ constexpr inline QColor papayawhip {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xef * 0x101, 0xd5 * 0x101};
+ constexpr inline QColor peachpuff {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xda * 0x101, 0xb9 * 0x101};
+ constexpr inline QColor peru {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x85 * 0x101, 0x3f * 0x101};
+ constexpr inline QColor pink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xc0 * 0x101, 0xcb * 0x101};
+ constexpr inline QColor plum {QColor::Rgb, 0xff * 0x101, 0xdd * 0x101, 0xa0 * 0x101, 0xdd * 0x101};
+ constexpr inline QColor powderblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xe0 * 0x101, 0xe6 * 0x101};
+ constexpr inline QColor purple {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr inline QColor rosybrown {QColor::Rgb, 0xff * 0x101, 0xbc * 0x101, 0x8f * 0x101, 0x8f * 0x101};
+ constexpr inline QColor royalblue {QColor::Rgb, 0xff * 0x101, 0x41 * 0x101, 0x69 * 0x101, 0xe1 * 0x101};
+ constexpr inline QColor saddlebrown {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x45 * 0x101, 0x13 * 0x101};
+ constexpr inline QColor salmon {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0x80 * 0x101, 0x72 * 0x101};
+ constexpr inline QColor sandybrown {QColor::Rgb, 0xff * 0x101, 0xf4 * 0x101, 0xa4 * 0x101, 0x60 * 0x101};
+ constexpr inline QColor seagreen {QColor::Rgb, 0xff * 0x101, 0x2e * 0x101, 0x8b * 0x101, 0x57 * 0x101};
+ constexpr inline QColor seashell {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf5 * 0x101, 0xee * 0x101};
+ constexpr inline QColor sienna {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0x52 * 0x101, 0x2d * 0x101};
+ constexpr inline QColor silver {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
+ constexpr inline QColor skyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xeb * 0x101};
+ constexpr inline QColor slateblue {QColor::Rgb, 0xff * 0x101, 0x6a * 0x101, 0x5a * 0x101, 0xcd * 0x101};
+ constexpr inline QColor slategray {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
+ constexpr inline QColor slategrey {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
+ constexpr inline QColor snow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101};
+ constexpr inline QColor springgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x7f * 0x101};
+ constexpr inline QColor steelblue {QColor::Rgb, 0xff * 0x101, 0x46 * 0x101, 0x82 * 0x101, 0xb4 * 0x101};
+ constexpr inline QColor tan {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0xb4 * 0x101, 0x8c * 0x101};
+ constexpr inline QColor teal {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr inline QColor thistle {QColor::Rgb, 0xff * 0x101, 0xd8 * 0x101, 0xbf * 0x101, 0xd8 * 0x101};
+ constexpr inline QColor tomato {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x63 * 0x101, 0x47 * 0x101};
+ constexpr inline QColor turquoise {QColor::Rgb, 0xff * 0x101, 0x40 * 0x101, 0xe0 * 0x101, 0xd0 * 0x101};
+ constexpr inline QColor violet {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0x82 * 0x101, 0xee * 0x101};
+ constexpr inline QColor wheat {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xde * 0x101, 0xb3 * 0x101};
+ constexpr inline QColor white {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr inline QColor whitesmoke {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xf5 * 0x101};
+ constexpr inline QColor yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr inline QColor yellowgreen {QColor::Rgb, 0xff * 0x101, 0x9a * 0x101, 0xcd * 0x101, 0x32 * 0x101};
} // namespace Svg
-#endif // Q_COMPILER_CONSTEXPR && Q_COMPILER_UNIFORM_INIT
} // namespace QColorLiterals
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolor_p.h b/src/gui/painting/qcolor_p.h
index b44f2b163a..89a31f66a4 100644
--- a/src/gui/painting/qcolor_p.h
+++ b/src/gui/painting/qcolor_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLOR_P_H
#define QCOLOR_P_H
@@ -54,9 +18,11 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtGui/qrgb.h"
+#include <optional>
+
QT_BEGIN_NAMESPACE
-bool qt_get_hex_rgb(const char *, QRgb *);
+std::optional<QRgb> qt_get_hex_rgb(const char *) Q_DECL_PURE_FUNCTION;
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolorclut_p.h b/src/gui/painting/qcolorclut_p.h
new file mode 100644
index 0000000000..d95e9701b7
--- /dev/null
+++ b/src/gui/painting/qcolorclut_p.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOLORCLUT_H
+#define QCOLORCLUT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qlist.h>
+#include <QtGui/private/qcolormatrix_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// A 3/4-dimensional lookup table compatible with ICC lut8, lut16, mAB, and mBA formats.
+class QColorCLUT
+{
+ inline static QColorVector interpolate(const QColorVector &a, const QColorVector &b, float t)
+ {
+ return a + (b - a) * t; // faster than std::lerp by assuming no super large or non-number floats
+ }
+ inline static void interpolateIn(QColorVector &a, const QColorVector &b, float t)
+ {
+ a += (b - a) * t;
+ }
+public:
+ uint32_t gridPointsX = 0;
+ uint32_t gridPointsY = 0;
+ uint32_t gridPointsZ = 0;
+ uint32_t gridPointsW = 1;
+ QList<QColorVector> table;
+
+ bool isEmpty() const { return table.isEmpty(); }
+
+ QColorVector apply(const QColorVector &v) const
+ {
+ Q_ASSERT(table.size() == gridPointsX * gridPointsY * gridPointsZ * gridPointsW);
+ QColorVector frac;
+ const float x = std::clamp(v.x, 0.0f, 1.0f) * (gridPointsX - 1);
+ const float y = std::clamp(v.y, 0.0f, 1.0f) * (gridPointsY - 1);
+ const float z = std::clamp(v.z, 0.0f, 1.0f) * (gridPointsZ - 1);
+ const float w = std::clamp(v.w, 0.0f, 1.0f) * (gridPointsW - 1);
+ const uint32_t lox = static_cast<uint32_t>(std::floor(x));
+ const uint32_t hix = std::min(lox + 1, gridPointsX - 1);
+ const uint32_t loy = static_cast<uint32_t>(std::floor(y));
+ const uint32_t hiy = std::min(loy + 1, gridPointsY - 1);
+ const uint32_t loz = static_cast<uint32_t>(std::floor(z));
+ const uint32_t hiz = std::min(loz + 1, gridPointsZ - 1);
+ const uint32_t low = static_cast<uint32_t>(std::floor(w));
+ const uint32_t hiw = std::min(low + 1, gridPointsW - 1);
+ frac.x = x - static_cast<float>(lox);
+ frac.y = y - static_cast<float>(loy);
+ frac.z = z - static_cast<float>(loz);
+ frac.w = w - static_cast<float>(low);
+ if (gridPointsW > 1) {
+ auto index = [&](qsizetype x, qsizetype y, qsizetype z, qsizetype w) -> qsizetype {
+ return x * gridPointsW * gridPointsZ * gridPointsY
+ + y * gridPointsW * gridPointsZ
+ + z * gridPointsW
+ + w;
+ };
+ QColorVector tmp[8];
+ // interpolate over w
+ tmp[0] = interpolate(table[index(lox, loy, loz, low)],
+ table[index(lox, loy, loz, hiw)], frac.w);
+ tmp[1] = interpolate(table[index(lox, loy, hiz, low)],
+ table[index(lox, loy, hiz, hiw)], frac.w);
+ tmp[2] = interpolate(table[index(lox, hiy, loz, low)],
+ table[index(lox, hiy, loz, hiw)], frac.w);
+ tmp[3] = interpolate(table[index(lox, hiy, hiz, low)],
+ table[index(lox, hiy, hiz, hiw)], frac.w);
+ tmp[4] = interpolate(table[index(hix, loy, loz, low)],
+ table[index(hix, loy, loz, hiw)], frac.w);
+ tmp[5] = interpolate(table[index(hix, loy, hiz, low)],
+ table[index(hix, loy, hiz, hiw)], frac.w);
+ tmp[6] = interpolate(table[index(hix, hiy, loz, low)],
+ table[index(hix, hiy, loz, hiw)], frac.w);
+ tmp[7] = interpolate(table[index(hix, hiy, hiz, low)],
+ table[index(hix, hiy, hiz, hiw)], frac.w);
+ // interpolate over z
+ for (int i = 0; i < 4; ++i)
+ interpolateIn(tmp[i * 2], tmp[i * 2 + 1], frac.z);
+ // interpolate over y
+ for (int i = 0; i < 2; ++i)
+ interpolateIn(tmp[i * 4], tmp[i * 4 + 2], frac.y);
+ // interpolate over x
+ interpolateIn(tmp[0], tmp[4], frac.x);
+ return tmp[0];
+ }
+ auto index = [&](qsizetype x, qsizetype y, qsizetype z) -> qsizetype {
+ return x * gridPointsZ * gridPointsY
+ + y * gridPointsZ
+ + z;
+ };
+ QColorVector tmp[8] = {
+ table[index(lox, loy, loz)],
+ table[index(lox, loy, hiz)],
+ table[index(lox, hiy, loz)],
+ table[index(lox, hiy, hiz)],
+ table[index(hix, loy, loz)],
+ table[index(hix, loy, hiz)],
+ table[index(hix, hiy, loz)],
+ table[index(hix, hiy, hiz)]
+ };
+ // interpolate over z
+ for (int i = 0; i < 4; ++i)
+ interpolateIn(tmp[i * 2], tmp[i * 2 + 1], frac.z);
+ // interpolate over y
+ for (int i = 0; i < 2; ++i)
+ interpolateIn(tmp[i * 4], tmp[i * 4 + 2], frac.y);
+ // interpolate over x
+ interpolateIn(tmp[0], tmp[4], frac.x);
+ return tmp[0];
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOLORCLUT_H
diff --git a/src/gui/painting/qcolormatrix_p.h b/src/gui/painting/qcolormatrix_p.h
index 749aad3b2c..6a9b9f4f9a 100644
--- a/src/gui/painting/qcolormatrix_p.h
+++ b/src/gui/painting/qcolormatrix_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORMATRIX_H
#define QCOLORMATRIX_H
@@ -53,6 +17,8 @@
#include <QtGui/qtguiglobal.h>
#include <QtCore/qpoint.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qsimd_p.h>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -62,25 +28,24 @@ class QColorVector
{
public:
QColorVector() = default;
- Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z) { }
- explicit Q_DECL_CONSTEXPR QColorVector(const QPointF &chr) // from XY chromaticity
- : x(chr.x() / chr.y())
- , y(1.0f)
- , z((1.0 - chr.x() - chr.y()) / chr.y())
- { }
- float x = 0.0f; // X, x or red
- float y = 0.0f; // Y, y or green
- float z = 0.0f; // Z, Y or blue
- float _unused = 0.0f;
+ constexpr QColorVector(float x, float y, float z, float w = 0.0f) noexcept : x(x), y(y), z(z), w(w) { }
+ static constexpr QColorVector fromXYChromaticity(QPointF chr)
+ { return {float(chr.x() / chr.y()), 1.0f, float((1.0f - chr.x() - chr.y()) / chr.y())}; }
+ float x = 0.0f; // X, x, L, or red/cyan
+ float y = 0.0f; // Y, y, a, or green/magenta
+ float z = 0.0f; // Z, Y, b, or blue/yellow
+ float w = 0.0f; // unused, or black
- friend inline bool operator==(const QColorVector &v1, const QColorVector &v2);
- friend inline bool operator!=(const QColorVector &v1, const QColorVector &v2);
- bool isNull() const
+ constexpr bool isNull() const noexcept
{
- return !x && !y && !z;
+ return !x && !y && !z && !w;
+ }
+ bool isValid() const noexcept
+ {
+ return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
}
- static bool isValidChromaticity(const QPointF &chr)
+ static constexpr bool isValidChromaticity(const QPointF &chr)
{
if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0))
return false;
@@ -91,26 +56,149 @@ public:
return true;
}
+ constexpr QColorVector operator*(float f) const { return QColorVector(x * f, y * f, z * f, w * f); }
+ constexpr QColorVector operator+(const QColorVector &v) const { return QColorVector(x + v.x, y + v.y, z + v.z, w + v.w); }
+ constexpr QColorVector operator-(const QColorVector &v) const { return QColorVector(x - v.x, y - v.y, z - v.z, w - v.w); }
+ void operator+=(const QColorVector &v) { x += v.x; y += v.y; z += v.z; w += v.w; }
+
+ QPointF toChromaticity() const
+ {
+ if (isNull())
+ return QPointF();
+ float mag = 1.0f / (x + y + z);
+ return QPointF(x * mag, y * mag);
+ }
+
// Common whitepoints:
- static Q_DECL_CONSTEXPR QPointF D50Chromaticity() { return QPointF(0.34567, 0.35850); }
- static Q_DECL_CONSTEXPR QPointF D65Chromaticity() { return QPointF(0.31271, 0.32902); }
- static Q_DECL_CONSTEXPR QColorVector D50() { return QColorVector(D50Chromaticity()); }
- static Q_DECL_CONSTEXPR QColorVector D65() { return QColorVector(D65Chromaticity()); }
+ static constexpr QPointF D50Chromaticity() { return QPointF(0.34567, 0.35850); }
+ static constexpr QPointF D65Chromaticity() { return QPointF(0.31271, 0.32902); }
+ static constexpr QColorVector D50() { return fromXYChromaticity(D50Chromaticity()); }
+ static constexpr QColorVector D65() { return fromXYChromaticity(D65Chromaticity()); }
+
+ QColorVector xyzToLab() const
+ {
+ constexpr QColorVector ref = D50();
+ constexpr float eps = 0.008856f;
+ constexpr float kap = 903.3f;
+#if defined(__SSE2__)
+ const __m128 iref = _mm_setr_ps(1.f / ref.x, 1.f / ref.y, 1.f / ref.z, 0.f);
+ __m128 v = _mm_loadu_ps(&x);
+ v = _mm_mul_ps(v, iref);
+
+ const __m128 f3 = _mm_set1_ps(3.f);
+ __m128 est = _mm_add_ps(_mm_set1_ps(0.25f), _mm_mul_ps(v, _mm_set1_ps(0.75f))); // float est = 0.25f + (x * 0.75f);
+ __m128 estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+
+ __m128 kapmul = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v, _mm_set1_ps(kap)), _mm_set1_ps(16.f)),
+ _mm_set1_ps(1.f / 116.f)); // f_ = (kap * f_ + 16.f) * (1.f / 116.f);
+ __m128 cmpgt = _mm_cmpgt_ps(v, _mm_set1_ps(eps)); // if (f_ > eps)
+#if defined(__SSE4_1__)
+ v = _mm_blendv_ps(kapmul, est, cmpgt); // if (..) f_ =.. else f_ =..
+#else
+ v = _mm_or_ps(_mm_and_ps(cmpgt, est), _mm_andnot_ps(cmpgt, kapmul));
+#endif
+ alignas(16) float out[4];
+ _mm_store_ps(out, v);
+ const float L = 116.f * out[1] - 16.f;
+ const float a = 500.f * (out[0] - out[1]);
+ const float b = 200.f * (out[1] - out[2]);
+#else
+ float xr = x * (1.f / ref.x);
+ float yr = y * (1.f / ref.y);
+ float zr = z * (1.f / ref.z);
+
+ float fx, fy, fz;
+ if (xr > eps)
+ fx = fastCbrt(xr);
+ else
+ fx = (kap * xr + 16.f) * (1.f / 116.f);
+ if (yr > eps)
+ fy = fastCbrt(yr);
+ else
+ fy = (kap * yr + 16.f) * (1.f / 116.f);
+ if (zr > eps)
+ fz = fastCbrt(zr);
+ else
+ fz = (kap * zr + 16.f) * (1.f / 116.f);
+
+ const float L = 116.f * fy - 16.f;
+ const float a = 500.f * (fx - fy);
+ const float b = 200.f * (fy - fz);
+#endif
+ // We output Lab values that has been scaled to 0.0->1.0 values, see also labToXyz.
+ return QColorVector(L * (1.f / 100.f), (a + 128.f) * (1.f / 255.f), (b + 128.f) * (1.f / 255.f));
+ }
+
+ QColorVector labToXyz() const
+ {
+ constexpr QColorVector ref = D50();
+ constexpr float eps = 0.008856f;
+ constexpr float kap = 903.3f;
+ // This transform has been guessed from the ICC spec, but it is not stated
+ // anywhere to be the one to use to map to and from 0.0->1.0 values:
+ const float L = x * 100.f;
+ const float a = (y * 255.f) - 128.f;
+ const float b = (z * 255.f) - 128.f;
+ // From here is official Lab->XYZ conversion:
+ float fy = (L + 16.f) * (1.f / 116.f);
+ float fx = fy + (a * (1.f / 500.f));
+ float fz = fy - (b * (1.f / 200.f));
+
+ float xr, yr, zr;
+ if (fx * fx * fx > eps)
+ xr = fx * fx * fx;
+ else
+ xr = (116.f * fx - 16) * (1.f / kap);
+ if (L > (kap * eps))
+ yr = fy * fy * fy;
+ else
+ yr = L * (1.f / kap);
+ if (fz * fz * fz > eps)
+ zr = fz * fz * fz;
+ else
+ zr = (116.f * fz - 16) * (1.f / kap);
+
+ xr = xr * ref.x;
+ yr = yr * ref.y;
+ zr = zr * ref.z;
+ return QColorVector(xr, yr, zr);
+ }
+ friend inline bool comparesEqual(const QColorVector &lhs, const QColorVector &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QColorVector);
+
+private:
+ static float fastCbrt(float x)
+ {
+ // This gives us cube root within the precision we need.
+ float est = 0.25f + (x * 0.75f); // guessing a cube-root of numbers between 0.01 and 1.
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ // Q_ASSERT(qAbs(est - std::cbrt(x)) < 0.0001f);
+ return est;
+ }
};
-inline bool operator==(const QColorVector &v1, const QColorVector &v2)
+inline bool comparesEqual(const QColorVector &v1, const QColorVector &v2)
{
return (std::abs(v1.x - v2.x) < (1.0f / 2048.0f))
&& (std::abs(v1.y - v2.y) < (1.0f / 2048.0f))
- && (std::abs(v1.z - v2.z) < (1.0f / 2048.0f));
-}
-
-inline bool operator!=(const QColorVector &v1, const QColorVector &v2)
-{
- return !(v1 == v2);
+ && (std::abs(v1.z - v2.z) < (1.0f / 2048.0f))
+ && (std::abs(v1.w - v2.w) < (1.0f / 2048.0f));
}
-
// A matrix mapping 3 value colors.
// Not using QTransform because only floats are needed and performance is critical.
class QColorMatrix
@@ -121,27 +209,29 @@ public:
QColorVector g;
QColorVector b;
- friend inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2);
- friend inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2);
-
- bool isNull() const
+ constexpr bool isNull() const
{
return r.isNull() && g.isNull() && b.isNull();
}
+ constexpr float determinant() const
+ {
+ return r.x * (b.z * g.y - g.z * b.y) -
+ r.y * (b.z * g.x - g.z * b.x) +
+ r.z * (b.y * g.x - g.y * b.x);
+ }
bool isValid() const
{
// A color matrix must be invertible
- float det = r.x * (b.z * g.y - g.z * b.y) -
- r.y * (b.z * g.x - g.z * b.x) +
- r.z * (b.y * g.x - g.y * b.x);
- return !qFuzzyIsNull(det);
+ return std::isnormal(determinant());
+ }
+ bool isIdentity() const noexcept
+ {
+ return *this == identity();
}
QColorMatrix inverted() const
{
- float det = r.x * (b.z * g.y - g.z * b.y) -
- r.y * (b.z * g.x - g.z * b.x) +
- r.z * (b.y * g.x - g.y * b.x);
+ float det = determinant();
det = 1.0f / det;
QColorMatrix inv;
inv.r.x = (g.y * b.z - b.y * g.z) * det;
@@ -155,20 +245,20 @@ public:
inv.b.z = (r.x * g.y - g.x * r.y) * det;
return inv;
}
- QColorMatrix operator*(const QColorMatrix &o) const
+ friend inline constexpr QColorMatrix operator*(const QColorMatrix &a, const QColorMatrix &o)
{
QColorMatrix comb;
- comb.r.x = r.x * o.r.x + g.x * o.r.y + b.x * o.r.z;
- comb.g.x = r.x * o.g.x + g.x * o.g.y + b.x * o.g.z;
- comb.b.x = r.x * o.b.x + g.x * o.b.y + b.x * o.b.z;
+ comb.r.x = a.r.x * o.r.x + a.g.x * o.r.y + a.b.x * o.r.z;
+ comb.g.x = a.r.x * o.g.x + a.g.x * o.g.y + a.b.x * o.g.z;
+ comb.b.x = a.r.x * o.b.x + a.g.x * o.b.y + a.b.x * o.b.z;
- comb.r.y = r.y * o.r.x + g.y * o.r.y + b.y * o.r.z;
- comb.g.y = r.y * o.g.x + g.y * o.g.y + b.y * o.g.z;
- comb.b.y = r.y * o.b.x + g.y * o.b.y + b.y * o.b.z;
+ comb.r.y = a.r.y * o.r.x + a.g.y * o.r.y + a.b.y * o.r.z;
+ comb.g.y = a.r.y * o.g.x + a.g.y * o.g.y + a.b.y * o.g.z;
+ comb.b.y = a.r.y * o.b.x + a.g.y * o.b.y + a.b.y * o.b.z;
- comb.r.z = r.z * o.r.x + g.z * o.r.y + b.z * o.r.z;
- comb.g.z = r.z * o.g.x + g.z * o.g.y + b.z * o.g.z;
- comb.b.z = r.z * o.b.x + g.z * o.b.y + b.z * o.b.z;
+ comb.r.z = a.r.z * o.r.x + a.g.z * o.r.y + a.b.z * o.r.z;
+ comb.g.z = a.r.z * o.g.x + a.g.z * o.g.y + a.b.z * o.g.z;
+ comb.b.z = a.r.z * o.b.x + a.g.z * o.b.y + a.b.z * o.b.z;
return comb;
}
@@ -195,6 +285,32 @@ public:
{ 0.0f, v.y, 0.0f },
{ 0.0f, 0.0f, v.z } };
}
+ static QColorMatrix chromaticAdaptation(const QColorVector &whitePoint)
+ {
+ constexpr QColorVector whitePointD50 = QColorVector::D50();
+ if (whitePoint != whitePointD50) {
+ // A chromatic adaptation to map a white point to XYZ D50.
+
+ // The Bradford method chromatic adaptation matrix:
+ const QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
+ { 0.2664f, 1.7135f, -0.0685f },
+ { -0.1614f, 0.0367f, 1.0296f } };
+ const QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
+ { -0.1470543f, 0.5183603f, 0.0400428f },
+ { 0.1599627f, 0.0492912f, 0.9684867f } };
+
+ const QColorVector srcCone = abrad.map(whitePoint);
+ if (srcCone.x && srcCone.y && srcCone.z) {
+ const QColorVector dstCone = abrad.map(whitePointD50);
+ const QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
+ { 0, dstCone.y / srcCone.y, 0 },
+ { 0, 0, dstCone.z / srcCone.z } };
+ return abradinv * (wToD50 * abrad);
+ }
+ }
+ return QColorMatrix::identity();
+ }
+
// These are used to recognize matrices from ICC profiles:
static QColorMatrix toXyzFromSRgb()
{
@@ -220,18 +336,15 @@ public:
{ 0.1351922452f, 0.7118769884f, 0.0000000000f },
{ 0.0313525312f, 0.0000856627f, 0.8251883388f } };
}
+ friend inline bool comparesEqual(const QColorMatrix &lhs, const QColorMatrix &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QColorMatrix);
};
-inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2)
+inline bool comparesEqual(const QColorMatrix &m1, const QColorMatrix &m2)
{
return (m1.r == m2.r) && (m1.g == m2.g) && (m1.b == m2.b);
}
-inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2)
-{
- return !(m1 == m2);
-}
-
QT_END_NAMESPACE
#endif // QCOLORMATRIX_P_H
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 43efdc1166..7a1d34a408 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -1,51 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcolorspace.h"
#include "qcolorspace_p.h"
#include "qcolortransform.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolortransferfunction_p.h"
#include "qcolortransform_p.h"
#include "qicc_p.h"
+#include <qatomic.h>
#include <qmath.h>
#include <qtransform.h>
@@ -53,7 +19,19 @@
QT_BEGIN_NAMESPACE
-QBasicMutex QColorSpacePrivate::s_lutWriteLock;
+Q_CONSTINIT QBasicMutex QColorSpacePrivate::s_lutWriteLock;
+
+Q_CONSTINIT static QAtomicPointer<QColorSpacePrivate> s_predefinedColorspacePrivates[QColorSpace::ProPhotoRgb] = {};
+static void cleanupPredefinedColorspaces()
+{
+ for (QAtomicPointer<QColorSpacePrivate> &ptr : s_predefinedColorspacePrivates) {
+ QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(nullptr);
+ if (prv && !prv->ref.deref())
+ delete prv;
+ }
+}
+
+Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces)
QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
{
@@ -103,45 +81,19 @@ bool QColorSpacePrimaries::areValid() const
QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
{
// This converts to XYZ in some undefined scale.
- QColorMatrix toXyz = { QColorVector(redPoint),
- QColorVector(greenPoint),
- QColorVector(bluePoint) };
+ QColorMatrix toXyz = { QColorVector::fromXYChromaticity(redPoint),
+ QColorVector::fromXYChromaticity(greenPoint),
+ QColorVector::fromXYChromaticity(bluePoint) };
// Since the white point should be (1.0, 1.0, 1.0) in the
// input, we can figure out the scale by using the
// inverse conversion on the white point.
- QColorVector wXyz(whitePoint);
+ const auto wXyz = QColorVector::fromXYChromaticity(whitePoint);
QColorVector whiteScale = toXyz.inverted().map(wXyz);
// Now we have scaled conversion to XYZ relative to the given whitepoint
toXyz = toXyz * QColorMatrix::fromScale(whiteScale);
- // But we want a conversion to XYZ relative to D50
- QColorVector wXyzD50 = QColorVector::D50();
-
- if (wXyz != wXyzD50) {
- // Do chromatic adaptation to map our white point to XYZ D50.
-
- // The Bradford method chromatic adaptation matrix:
- QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
- { 0.2664f, 1.7135f, -0.0685f },
- { -0.1614f, 0.0367f, 1.0296f } };
- QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
- { -0.1470543f, 0.5183603f, 0.0400428f },
- { 0.1599627f, 0.0492912f, 0.9684867f } };
-
- QColorVector srcCone = abrad.map(wXyz);
- QColorVector dstCone = abrad.map(wXyzD50);
-
- QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
- { 0, dstCone.y / srcCone.y, 0 },
- { 0, 0, dstCone.z / srcCone.z } };
-
-
- QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad);
- toXyz = chromaticAdaptation * toXyz;
- }
-
return toXyz;
}
@@ -151,6 +103,7 @@ QColorSpacePrivate::QColorSpacePrivate()
QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
: namedColorSpace(namedColorSpace)
+ , colorModel(QColorSpace::ColorModel::Rgb)
{
switch (namedColorSpace) {
case QColorSpace::SRgb:
@@ -185,9 +138,10 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSp
initialize();
}
-QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma)
+QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma)
: primaries(primaries)
- , transferFunction(fun)
+ , transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(gamma)
{
identifyColorSpace();
@@ -195,19 +149,97 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorS
}
QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
- QColorSpace::TransferFunction fun,
+ QColorSpace::TransferFunction transferFunction,
float gamma)
: primaries(QColorSpace::Primaries::Custom)
- , transferFunction(fun)
+ , transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(gamma)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
- whitePoint = QColorVector(primaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
+
identifyColorSpace();
setTransferFunction();
}
+QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint,
+ QColorSpace::TransferFunction transferFunction,
+ float gamma)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Gray)
+ , gamma(gamma)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
+{
+ chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
+ toXyz = chad;
+ setTransferFunction();
+}
+
+QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Gray)
+ , gamma(0)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
+{
+ chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
+ toXyz = chad;
+ setTransferFunctionTable(transferFunctionTable);
+ setTransferFunction();
+}
+
+QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, const QList<uint16_t> &transferFunctionTable)
+ : primaries(primaries)
+ , transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
+ , gamma(0)
+{
+ setTransferFunctionTable(transferFunctionTable);
+ identifyColorSpace();
+ initialize();
+}
+
+QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, const QList<uint16_t> &transferFunctionTable)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
+ , gamma(0)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
+{
+ Q_ASSERT(primaries.areValid());
+ toXyz = primaries.toXyzMatrix();
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
+ setTransferFunctionTable(transferFunctionTable);
+ identifyColorSpace();
+ initialize();
+}
+
+QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
+ const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
+ , gamma(0)
+{
+ Q_ASSERT(primaries.areValid());
+ toXyz = primaries.toXyzMatrix();
+ whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
+ setTransferFunctionTables(redTransferFunctionTable,
+ greenTransferFunctionTable,
+ blueTransferFunctionTable);
+ identifyColorSpace();
+}
+
void QColorSpacePrivate::identifyColorSpace()
{
switch (primaries) {
@@ -282,7 +314,76 @@ void QColorSpacePrivate::setToXyzMatrix()
}
QColorSpacePrimaries colorSpacePrimaries(primaries);
toXyz = colorSpacePrimaries.toXyzMatrix();
- whitePoint = QColorVector(colorSpacePrimaries.whitePoint);
+ whitePoint = QColorVector::fromXYChromaticity(colorSpacePrimaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
+}
+
+void QColorSpacePrivate::setTransferFunctionTable(const QList<uint16_t> &transferFunctionTable)
+{
+ QColorTransferTable table(transferFunctionTable.size(), transferFunctionTable);
+ if (!table.isEmpty() && !table.checkValidity()) {
+ qWarning() << "Invalid transfer function table given to QColorSpace";
+ trc[0].m_type = QColorTrc::Type::Uninitialized;
+ return;
+ }
+ transferFunction = QColorSpace::TransferFunction::Custom;
+ QColorTransferFunction curve;
+ if (table.asColorTransferFunction(&curve)) {
+ // Table recognized as a specific curve
+ if (curve.isIdentity()) {
+ transferFunction = QColorSpace::TransferFunction::Linear;
+ gamma = 1.0f;
+ } else if (curve.isSRgb()) {
+ transferFunction = QColorSpace::TransferFunction::SRgb;
+ }
+ trc[0].m_type = QColorTrc::Type::Function;
+ trc[0].m_fun = curve;
+ } else {
+ trc[0].m_type = QColorTrc::Type::Table;
+ trc[0].m_table = table;
+ }
+}
+
+void QColorSpacePrivate::setTransferFunctionTables(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable)
+{
+ QColorTransferTable redTable(redTransferFunctionTable.size(), redTransferFunctionTable);
+ QColorTransferTable greenTable(greenTransferFunctionTable.size(), greenTransferFunctionTable);
+ QColorTransferTable blueTable(blueTransferFunctionTable.size(), blueTransferFunctionTable);
+ if (!redTable.isEmpty() && !greenTable.isEmpty() && !blueTable.isEmpty() &&
+ !redTable.checkValidity() && !greenTable.checkValidity() && !blueTable.checkValidity()) {
+ qWarning() << "Invalid transfer function table given to QColorSpace";
+ trc[0].m_type = QColorTrc::Type::Uninitialized;
+ trc[1].m_type = QColorTrc::Type::Uninitialized;
+ trc[2].m_type = QColorTrc::Type::Uninitialized;
+ return;
+ }
+ transferFunction = QColorSpace::TransferFunction::Custom;
+ QColorTransferFunction curve;
+ if (redTable.asColorTransferFunction(&curve)) {
+ trc[0].m_type = QColorTrc::Type::Function;
+ trc[0].m_fun = curve;
+ } else {
+ trc[0].m_type = QColorTrc::Type::Table;
+ trc[0].m_table = redTable;
+ }
+ if (greenTable.asColorTransferFunction(&curve)) {
+ trc[1].m_type = QColorTrc::Type::Function;
+ trc[1].m_fun = curve;
+ } else {
+ trc[1].m_type = QColorTrc::Type::Table;
+ trc[1].m_table = greenTable;
+ }
+ if (blueTable.asColorTransferFunction(&curve)) {
+ trc[2].m_type = QColorTrc::Type::Function;
+ trc[2].m_fun = curve;
+ } else {
+ trc[2].m_type = QColorTrc::Type::Table;
+ trc[2].m_table = blueTable;
+ }
+ lut.generated.storeRelease(0);
}
void QColorSpacePrivate::setTransferFunction()
@@ -318,6 +419,7 @@ void QColorSpacePrivate::setTransferFunction()
}
trc[1] = trc[0];
trc[2] = trc[0];
+ lut.generated.storeRelease(0);
}
QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpacePrivate *out) const
@@ -326,13 +428,52 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
QColorTransform combined;
auto ptr = new QColorTransformPrivate;
combined.d = ptr;
- combined.d->ref.ref();
ptr->colorSpaceIn = this;
ptr->colorSpaceOut = out;
- ptr->colorMatrix = out->toXyz.inverted() * toXyz;
+ if (isThreeComponentMatrix())
+ ptr->colorMatrix = toXyz;
+ else
+ ptr->colorMatrix = QColorMatrix::identity();
+ if (out->isThreeComponentMatrix())
+ ptr->colorMatrix = out->toXyz.inverted() * ptr->colorMatrix;
+ if (ptr->isIdentity())
+ return QColorTransform();
return combined;
}
+QColorTransform QColorSpacePrivate::transformationToXYZ() const
+{
+ QColorTransform transform;
+ auto ptr = new QColorTransformPrivate;
+ transform.d = ptr;
+ ptr->colorSpaceIn = this;
+ ptr->colorSpaceOut = this;
+ // Convert to XYZ relative to our white point, not the regular D50 white point.
+ if (isThreeComponentMatrix())
+ ptr->colorMatrix = QColorMatrix::chromaticAdaptation(whitePoint).inverted() * toXyz;
+ else
+ ptr->colorMatrix = QColorMatrix::identity();
+ return transform;
+}
+
+bool QColorSpacePrivate::isThreeComponentMatrix() const
+{
+ return transformModel == QColorSpace::TransformModel::ThreeComponentMatrix;
+}
+
+void QColorSpacePrivate::clearElementListProcessingForEdit()
+{
+ Q_ASSERT(transformModel == QColorSpace::TransformModel::ElementListProcessing);
+ Q_ASSERT(primaries == QColorSpace::Primaries::Custom);
+ Q_ASSERT(transferFunction == QColorSpace::TransferFunction::Custom);
+
+ transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
+ colorModel = QColorSpace::ColorModel::Rgb;
+ isPcsLab = false;
+ mAB.clear();
+ mBA.clear();
+}
+
/*!
\class QColorSpace
\brief The QColorSpace class provides a color space abstraction.
@@ -355,9 +496,10 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
A color space can generally speaking be conceived as a combination of set of primary
colors and a transfer function. The primaries defines the axes of the color space, and
the transfer function how values are mapped on the axes.
- The primaries are defined by three primary colors that represent exactly how red, green,
- and blue look in this particular color space, and a white color that represents where
- and how bright pure white is. The range of colors expressable by the primary colors is
+ The primaries are for ColorModel::Rgb color spaces defined by three primary colors that
+ represent exactly how red, green, and blue look in this particular color space, and a white
+ color that represents where and how bright pure white is. For grayscale color spaces, only
+ a single white primary is needed. The range of colors expressible by the primary colors is
called the gamut, and a color space that can represent a wider range of colors is also
known as a wide-gamut color space.
@@ -411,11 +553,39 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
*/
/*!
+ \enum QColorSpace::TransformModel
+ \since 6.8
+
+ Defines the processing model used for color space transforms.
+
+ \value ThreeComponentMatrix The transform consist of a matrix calculated from primaries and set of transfer functions
+ for each color channel. This is very fast and used by all predefined color spaces. Any color space on this form is
+ reversible and always both valid sources and targets.
+ \value ElementListProcessing The transforms are one or two lists of processing elements that can do many things,
+ each list only process either to the connection color space or from it. This is very flexible, but rather
+ slow, and can only be set by reading ICC profiles (See \l fromIccProfile()). Since the two lists are
+ separate a color space on this form can be a valid source, but not necessarily also a valid target. When changing
+ either primaries or transfer function on a color space on this type it will reset to an empty ThreeComponentMatrix form.
+*/
+
+/*!
+ \enum QColorSpace::ColorModel
+ \since 6.8
+
+ Defines the color model used by the color space data.
+
+ \value Undefined No color model
+ \value Rgb An RGB color model with red, green, and blue colors. Can apply to RGB and grayscale data.
+ \value Gray A gray scale color model. Can only apply to grayscale data.
+ \value Cmyk Can only represent color data defined with cyan, magenta, yellow, and black colors.
+ In effect only QImage::Format_CMYK32. Note Cmyk color spaces will be TransformModel::ElementListProcessing.
+*/
+
+/*!
+ \fn QColorSpace::QColorSpace()
+
Creates a new colorspace object that represents an undefined and invalid colorspace.
*/
-QColorSpace::QColorSpace()
-{
-}
/*!
Creates a new colorspace object that represents a \a namedColorSpace.
@@ -426,24 +596,28 @@ QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace);
return;
}
- static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
- if (!predefinedColorspacePrivates[namedColorSpace]) {
- predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
- predefinedColorspacePrivates[namedColorSpace]->ref.ref();
+ // The defined namespaces start at 1:
+ auto &atomicRef = s_predefinedColorspacePrivates[static_cast<int>(namedColorSpace) - 1];
+ QColorSpacePrivate *cspriv = atomicRef.loadAcquire();
+ if (!cspriv) {
+ auto *tmp = new QColorSpacePrivate(namedColorSpace);
+ tmp->ref.ref();
+ if (atomicRef.testAndSetOrdered(nullptr, tmp, cspriv))
+ cspriv = tmp;
+ else
+ delete tmp;
}
- d_ptr = predefinedColorspacePrivates[namedColorSpace];
- d_ptr->ref.ref();
+ d_ptr = cspriv;
Q_ASSERT(isValid());
}
/*!
- Creates a custom color space with the primaries \a primaries, using the transfer function \a fun and
+ Creates a custom color space with the primaries \a primaries, using the transfer function \a transferFunction and
optionally \a gamma.
*/
-QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma)
- : d_ptr(new QColorSpacePrivate(primaries, fun, gamma))
+QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma)
+ : d_ptr(new QColorSpacePrivate(primaries, transferFunction, gamma))
{
- d_ptr->ref.ref();
}
/*!
@@ -453,51 +627,99 @@ QColorSpace::QColorSpace(QColorSpace::Primaries primaries, QColorSpace::Transfer
QColorSpace::QColorSpace(QColorSpace::Primaries primaries, float gamma)
: d_ptr(new QColorSpacePrivate(primaries, TransferFunction::Gamma, gamma))
{
- d_ptr->ref.ref();
+}
+
+/*!
+ Creates a custom color space with the primaries \a gamut, using a custom transfer function
+ described by \a transferFunctionTable.
+
+ The table should contain at least 2 values, and contain an monotonically increasing list
+ of values from 0 to 65535.
+
+ \since 6.1
+ */
+QColorSpace::QColorSpace(QColorSpace::Primaries gamut, const QList<uint16_t> &transferFunctionTable)
+ : d_ptr(new QColorSpacePrivate(gamut, transferFunctionTable))
+{
+}
+
+/*!
+ Creates a custom grayscale color space with the white point \a whitePoint, using the transfer function \a transferFunction and
+ optionally \a gamma.
+
+ \since 6.8
+*/
+QColorSpace::QColorSpace(const QPointF &whitePoint, TransferFunction transferFunction, float gamma)
+ : d_ptr(new QColorSpacePrivate(whitePoint, transferFunction, gamma))
+{
+}
+
+/*!
+ Creates a custom grayscale color space with white point \a whitePoint, and using the custom transfer function described by
+ \a transferFunctionTable.
+
+ \since 6.8
+*/
+QColorSpace::QColorSpace(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable)
+ : d_ptr(new QColorSpacePrivate(whitePoint, transferFunctionTable))
+{
}
/*!
Creates a custom colorspace with a primaries based on the chromaticities of the primary colors \a whitePoint,
- \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a fun and optionally \a gamma.
+ \a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a transferFunction and optionally \a gamma.
*/
QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint,
- QColorSpace::TransferFunction fun, float gamma)
+ QColorSpace::TransferFunction transferFunction, float gamma)
{
QColorSpacePrimaries primaries(whitePoint, redPoint, greenPoint, bluePoint);
if (!primaries.areValid()) {
qWarning() << "QColorSpace attempted constructed from invalid primaries:" << whitePoint << redPoint << greenPoint << bluePoint;
- d_ptr = nullptr;
return;
}
- d_ptr = new QColorSpacePrivate(primaries, fun, gamma);
- d_ptr->ref.ref();
+ d_ptr = new QColorSpacePrivate(primaries, transferFunction, gamma);
}
-QColorSpace::~QColorSpace()
-{
- if (d_ptr && !d_ptr->ref.deref())
- delete d_ptr;
-}
+/*!
+ Creates a custom color space with primaries based on the chromaticities of the primary colors \a whitePoint,
+ \a redPoint, \a greenPoint and \a bluePoint, and using the custom transfer function described by
+ \a transferFunctionTable.
-QColorSpace::QColorSpace(const QColorSpace &colorSpace)
- : d_ptr(colorSpace.d_ptr)
+ \since 6.1
+ */
+QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
+ const QPointF &greenPoint, const QPointF &bluePoint,
+ const QList<uint16_t> &transferFunctionTable)
+ : d_ptr(new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint}, transferFunctionTable))
{
- if (d_ptr)
- d_ptr->ref.ref();
}
-QColorSpace &QColorSpace::operator=(const QColorSpace &colorSpace)
+/*!
+ Creates a custom color space with primaries based on the chromaticities of the primary colors \a whitePoint,
+ \a redPoint, \a greenPoint and \a bluePoint, and using the custom transfer functions described by
+ \a redTransferFunctionTable, \a greenTransferFunctionTable, and \a blueTransferFunctionTable.
+
+ \since 6.1
+ */
+QColorSpace::QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
+ const QPointF &greenPoint, const QPointF &bluePoint,
+ const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable)
+ : d_ptr(new QColorSpacePrivate({whitePoint, redPoint, greenPoint, bluePoint},
+ redTransferFunctionTable,
+ greenTransferFunctionTable,
+ blueTransferFunctionTable))
{
- QColorSpacePrivate *oldD = d_ptr;
- d_ptr = colorSpace.d_ptr;
- if (d_ptr)
- d_ptr->ref.ref();
- if (oldD && !oldD->ref.deref())
- delete oldD;
- return *this;
}
+QColorSpace::~QColorSpace() = default;
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QColorSpacePrivate)
+
+QColorSpace::QColorSpace(const QColorSpace &colorSpace) noexcept = default;
+
/*! \fn void QColorSpace::swap(QColorSpace &other)
Swaps color space \a other with this color space. This operation is very fast and
@@ -553,13 +775,15 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc
return;
if (!d_ptr) {
d_ptr = new QColorSpacePrivate(Primaries::Custom, transferFunction, gamma);
- d_ptr->ref.ref();
return;
}
if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
return;
- QColorSpacePrivate::getWritable(*this); // detach
- d_ptr->description.clear();
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->transferFunction = transferFunction;
d_ptr->gamma = gamma;
d_ptr->identifyColorSpace();
@@ -567,6 +791,61 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc
}
/*!
+ Sets the transfer function to \a transferFunctionTable.
+
+ \since 6.1
+ \sa withTransferFunction()
+*/
+void QColorSpace::setTransferFunction(const QList<uint16_t> &transferFunctionTable)
+{
+ if (!d_ptr) {
+ d_ptr = new QColorSpacePrivate(Primaries::Custom, transferFunctionTable);
+ d_ptr->ref.ref();
+ return;
+ }
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
+ d_ptr->setTransferFunctionTable(transferFunctionTable);
+ d_ptr->gamma = 0;
+ d_ptr->identifyColorSpace();
+ d_ptr->setTransferFunction();
+}
+
+/*!
+ Sets the transfer functions to \a redTransferFunctionTable,
+ \a greenTransferFunctionTable and \a blueTransferFunctionTable.
+
+ \since 6.1
+ \sa withTransferFunctions()
+*/
+void QColorSpace::setTransferFunctions(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable)
+{
+ if (!d_ptr) {
+ d_ptr = new QColorSpacePrivate();
+ d_ptr->setTransferFunctionTables(redTransferFunctionTable,
+ greenTransferFunctionTable,
+ blueTransferFunctionTable);
+ d_ptr->ref.ref();
+ return;
+ }
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
+ d_ptr->setTransferFunctionTables(redTransferFunctionTable,
+ greenTransferFunctionTable,
+ blueTransferFunctionTable);
+ d_ptr->gamma = 0;
+ d_ptr->identifyColorSpace();
+}
+
+/*!
Returns a copy of this color space, except using the transfer function
\a transferFunction and \a gamma.
@@ -574,7 +853,7 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc
*/
QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction transferFunction, float gamma) const
{
- if (!isValid() || transferFunction == QColorSpace::TransferFunction::Custom)
+ if (!isValid() || transferFunction == TransferFunction::Custom)
return *this;
if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
return *this;
@@ -584,6 +863,41 @@ QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction tran
}
/*!
+ Returns a copy of this color space, except using the transfer function
+ described by \a transferFunctionTable.
+
+ \since 6.1
+ \sa transferFunction(), setTransferFunction()
+*/
+QColorSpace QColorSpace::withTransferFunction(const QList<uint16_t> &transferFunctionTable) const
+{
+ if (!isValid())
+ return *this;
+ QColorSpace out(*this);
+ out.setTransferFunction(transferFunctionTable);
+ return out;
+}
+
+/*!
+ Returns a copy of this color space, except using the transfer functions
+ described by \a redTransferFunctionTable, \a greenTransferFunctionTable and
+ \a blueTransferFunctionTable.
+
+ \since 6.1
+ \sa setTransferFunctions()
+*/
+QColorSpace QColorSpace::withTransferFunctions(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable) const
+{
+ if (!isValid())
+ return *this;
+ QColorSpace out(*this);
+ out.setTransferFunctions(redTransferFunctionTable, greenTransferFunctionTable, blueTransferFunctionTable);
+ return out;
+}
+
+/*!
Sets the primaries to those of the \a primariesId set.
\sa primaries()
@@ -594,14 +908,17 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
return;
if (!d_ptr) {
d_ptr = new QColorSpacePrivate(primariesId, TransferFunction::Custom, 0.0f);
- d_ptr->ref.ref();
return;
}
if (d_ptr->primaries == primariesId)
return;
- QColorSpacePrivate::getWritable(*this); // detach
- d_ptr->description.clear();
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->primaries = primariesId;
+ d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
d_ptr->identifyColorSpace();
d_ptr->setToXyzMatrix();
}
@@ -620,21 +937,114 @@ void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoin
return;
if (!d_ptr) {
d_ptr = new QColorSpacePrivate(primaries, TransferFunction::Custom, 0.0f);
- d_ptr->ref.ref();
return;
}
QColorMatrix toXyz = primaries.toXyzMatrix();
- if (QColorVector(primaries.whitePoint) == d_ptr->whitePoint && toXyz == d_ptr->toXyz)
+ QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector::fromXYChromaticity(whitePoint));
+ toXyz = chad * toXyz;
+ if (QColorVector::fromXYChromaticity(primaries.whitePoint) == d_ptr->whitePoint
+ && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
return;
- QColorSpacePrivate::getWritable(*this); // detach
- d_ptr->description.clear();
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->primaries = QColorSpace::Primaries::Custom;
+ d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
d_ptr->toXyz = toXyz;
- d_ptr->whitePoint = QColorVector(primaries.whitePoint);
+ d_ptr->chad = chad;
+ d_ptr->whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
+ d_ptr->identifyColorSpace();
+}
+
+/*!
+ Returns the white point used for this color space. Returns a null QPointF if not defined.
+
+ \since 6.8
+*/
+QPointF QColorSpace::whitePoint() const
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QPointF();
+ return d_ptr->whitePoint.toChromaticity();
+}
+
+/*!
+ Sets the white point to used for this color space to \a whitePoint.
+
+ \since 6.8
+*/
+void QColorSpace::setWhitePoint(const QPointF &whitePoint)
+{
+ if (Q_UNLIKELY(!d_ptr)) {
+ d_ptr = new QColorSpacePrivate(whitePoint, TransferFunction::Custom, 0.0f);
+ return;
+ }
+ if (QColorVector::fromXYChromaticity(whitePoint) == d_ptr->whitePoint)
+ return;
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
+ d_ptr->primaries = QColorSpace::Primaries::Custom;
+ // An RGB color model stays RGB, a gray stays gray, but an undefined one can now be considered gray
+ if (d_ptr->colorModel == QColorSpace::ColorModel::Undefined)
+ d_ptr->colorModel = QColorSpace::ColorModel::Gray;
+ QColorVector wXyz(QColorVector::fromXYChromaticity(whitePoint));
+ if (d_ptr->transformModel == QColorSpace::TransformModel::ThreeComponentMatrix) {
+ if (d_ptr->colorModel == QColorSpace::ColorModel::Rgb) {
+ // Rescale toXyz to new whitepoint
+ QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
+ QColorVector whiteScale = rawToXyz.inverted().map(wXyz);
+ rawToXyz = rawToXyz * QColorMatrix::fromScale(whiteScale);
+ d_ptr->chad = QColorMatrix::chromaticAdaptation(wXyz);
+ d_ptr->toXyz = d_ptr->chad * rawToXyz;
+ } else if (d_ptr->colorModel == QColorSpace::ColorModel::Gray) {
+ d_ptr->chad = d_ptr->toXyz = QColorMatrix::chromaticAdaptation(wXyz);
+ }
+ }
+ d_ptr->whitePoint = wXyz;
d_ptr->identifyColorSpace();
}
/*!
+ Returns the transfrom processing model used for this color space.
+
+ \since 6.8
+*/
+QColorSpace::TransformModel QColorSpace::transformModel() const noexcept
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QColorSpace::TransformModel::ThreeComponentMatrix;
+ return d_ptr->transformModel;
+}
+
+/*!
+ Returns the color model this color space can represent
+
+ \since 6.8
+*/
+QColorSpace::ColorModel QColorSpace::colorModel() const noexcept
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QColorSpace::ColorModel::Undefined;
+ return d_ptr->colorModel;
+}
+
+/*!
+ \internal
+*/
+void QColorSpace::detach()
+{
+ if (d_ptr)
+ d_ptr.detach();
+ else
+ d_ptr = new QColorSpacePrivate;
+}
+
+/*!
Returns an ICC profile representing the color space.
If the color space was generated from an ICC profile, that profile
@@ -661,14 +1071,11 @@ QByteArray QColorSpace::iccProfile() const
Creates a QColorSpace from ICC profile \a iccProfile.
\note Not all ICC profiles are supported. QColorSpace only supports
- RGB-XYZ ICC profiles that are three-component matrix-based.
+ RGB or Gray ICC profiles.
If the ICC profile is not supported an invalid QColorSpace is returned
where you can still read the original ICC profile using iccProfile().
- \note If the QByteArray data is created from external sources it should be
- at least 4 byte aligned.
-
\sa iccProfile()
*/
QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
@@ -676,90 +1083,232 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
QColorSpace colorSpace;
if (QIcc::fromIccProfile(iccProfile, &colorSpace))
return colorSpace;
- QColorSpacePrivate *d = QColorSpacePrivate::getWritable(colorSpace);
- d->iccProfile = iccProfile;
+ colorSpace.detach();
+ colorSpace.d_ptr->iccProfile = iccProfile;
return colorSpace;
}
/*!
- Returns \c true if the color space is valid.
+ Returns \c true if the color space is valid. For a color space with \c TransformModel::ThreeComponentMatrix
+ that means both primaries and transfer functions set, and implies isValidTarget().
+ For a color space with \c TransformModel::ElementListProcessing it means it has a valid source transform, to
+ check if it also a valid target color space use isValidTarget().
+
+ \sa isValidTarget()
*/
bool QColorSpace::isValid() const noexcept
{
- return d_ptr
- && d_ptr->toXyz.isValid()
- && d_ptr->trc[0].isValid() && d_ptr->trc[1].isValid() && d_ptr->trc[2].isValid();
+ if (!d_ptr)
+ return false;
+ return d_ptr->isValid();
}
/*!
- \relates QColorSpace
+ \since 6.8
+
+ Returns \c true if the color space is a valid target color space.
+*/
+bool QColorSpace::isValidTarget() const noexcept
+{
+ if (!d_ptr)
+ return false;
+ if (!d_ptr->isThreeComponentMatrix())
+ return !d_ptr->mBA.isEmpty();
+ return d_ptr->isValid();
+}
+
+/*!
+ \internal
+*/
+bool QColorSpacePrivate::isValid() const noexcept
+{
+ if (!isThreeComponentMatrix())
+ return !mAB.isEmpty();
+ if (!toXyz.isValid())
+ return false;
+ if (colorModel == QColorSpace::ColorModel::Gray) {
+ if (!trc[0].isValid())
+ return false;
+ } else {
+ if (!trc[0].isValid() || !trc[1].isValid() || !trc[2].isValid())
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn bool QColorSpace::operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
+
Returns \c true if colorspace \a colorSpace1 is equal to colorspace \a colorSpace2;
otherwise returns \c false
*/
-bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
+
+/*!
+ \fn bool QColorSpace::operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
+
+ Returns \c true if colorspace \a colorSpace1 is not equal to colorspace \a colorSpace2;
+ otherwise returns \c false
+*/
+
+static bool compareElement(const QColorSpacePrivate::TransferElement &element,
+ const QColorSpacePrivate::TransferElement &other)
{
- if (colorSpace1.d_ptr == colorSpace2.d_ptr)
+ return element.trc[0] == other.trc[0]
+ && element.trc[1] == other.trc[1]
+ && element.trc[2] == other.trc[2]
+ && element.trc[3] == other.trc[3];
+}
+
+static bool compareElement(const QColorMatrix &element,
+ const QColorMatrix &other)
+{
+ return element == other;
+}
+
+static bool compareElement(const QColorVector &element,
+ const QColorVector &other)
+{
+ return element == other;
+}
+
+static bool compareElement(const QColorCLUT &element,
+ const QColorCLUT &other)
+{
+ if (element.gridPointsX != other.gridPointsX)
+ return false;
+ if (element.gridPointsY != other.gridPointsY)
+ return false;
+ if (element.gridPointsZ != other.gridPointsZ)
+ return false;
+ if (element.gridPointsW != other.gridPointsW)
+ return false;
+ if (element.table.size() != other.table.size())
+ return false;
+ for (qsizetype i = 0; i < element.table.size(); ++i) {
+ if (element.table[i] != other.table[i])
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+static bool compareElements(const T &element, const QColorSpacePrivate::Element &other)
+{
+ return compareElement(element, std::get<T>(other));
+}
+
+/*!
+ \internal
+*/
+bool QColorSpace::equals(const QColorSpace &other) const
+{
+ if (d_ptr == other.d_ptr)
return true;
- if (!colorSpace1.d_ptr || !colorSpace2.d_ptr)
+ if (!d_ptr)
+ return false;
+ return d_ptr->equals(other.d_ptr.constData());
+}
+
+/*!
+ \internal
+*/
+bool QColorSpacePrivate::equals(const QColorSpacePrivate *other) const
+{
+ if (!other)
return false;
- if (colorSpace1.d_ptr->namedColorSpace && colorSpace2.d_ptr->namedColorSpace)
- return colorSpace1.d_ptr->namedColorSpace == colorSpace2.d_ptr->namedColorSpace;
+ if (namedColorSpace && other->namedColorSpace)
+ return namedColorSpace == other->namedColorSpace;
- const bool valid1 = colorSpace1.isValid();
- const bool valid2 = colorSpace2.isValid();
+ const bool valid1 = isValid();
+ const bool valid2 = other->isValid();
if (valid1 != valid2)
return false;
if (!valid1 && !valid2) {
- if (!colorSpace1.d_ptr->iccProfile.isEmpty() || !colorSpace2.d_ptr->iccProfile.isEmpty())
- return colorSpace1.d_ptr->iccProfile == colorSpace2.d_ptr->iccProfile;
+ if (!iccProfile.isEmpty() || !other->iccProfile.isEmpty())
+ return iccProfile == other->iccProfile;
+ return false;
}
// At this point one or both color spaces are unknown, and must be compared in detail instead
- if (colorSpace1.primaries() != QColorSpace::Primaries::Custom && colorSpace2.primaries() != QColorSpace::Primaries::Custom) {
- if (colorSpace1.primaries() != colorSpace2.primaries())
+ if (transformModel != other->transformModel)
+ return false;
+
+ if (!isThreeComponentMatrix()) {
+ if (isPcsLab != other->isPcsLab)
+ return false;
+ if (colorModel != other->colorModel)
+ return false;
+ if (mAB.count() != other->mAB.count())
+ return false;
+ if (mBA.count() != other->mBA.count())
+ return false;
+
+ // Compare element types
+ for (qsizetype i = 0; i < mAB.count(); ++i) {
+ if (mAB[i].index() != other->mAB[i].index())
+ return false;
+ }
+ for (qsizetype i = 0; i < mBA.count(); ++i) {
+ if (mBA[i].index() != other->mBA[i].index())
+ return false;
+ }
+
+ // Compare element contents
+ for (qsizetype i = 0; i < mAB.count(); ++i) {
+ if (!std::visit([&](auto &&elm) { return compareElements(elm, other->mAB[i]); }, mAB[i]))
+ return false;
+ }
+ for (qsizetype i = 0; i < mBA.count(); ++i) {
+ if (!std::visit([&](auto &&elm) { return compareElements(elm, other->mBA[i]); }, mBA[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ if (primaries != QColorSpace::Primaries::Custom && other->primaries != QColorSpace::Primaries::Custom) {
+ if (primaries != other->primaries)
return false;
} else {
- if (colorSpace1.d_ptr->toXyz != colorSpace2.d_ptr->toXyz)
+ if (toXyz != other->toXyz)
return false;
}
- if (colorSpace1.transferFunction() != QColorSpace::TransferFunction::Custom &&
- colorSpace2.transferFunction() != QColorSpace::TransferFunction::Custom) {
- if (colorSpace1.transferFunction() != colorSpace2.transferFunction())
+ if (transferFunction != QColorSpace::TransferFunction::Custom && other->transferFunction != QColorSpace::TransferFunction::Custom) {
+ if (transferFunction != other->transferFunction)
return false;
- if (colorSpace1.transferFunction() == QColorSpace::TransferFunction::Gamma)
- return (qAbs(colorSpace1.gamma() - colorSpace2.gamma()) <= (1.0f / 512.0f));
+ if (transferFunction == QColorSpace::TransferFunction::Gamma)
+ return (qAbs(gamma - other->gamma) <= (1.0f / 512.0f));
return true;
}
- if (colorSpace1.d_ptr->trc[0] != colorSpace2.d_ptr->trc[0] ||
- colorSpace1.d_ptr->trc[1] != colorSpace2.d_ptr->trc[1] ||
- colorSpace1.d_ptr->trc[2] != colorSpace2.d_ptr->trc[2])
+ if (trc[0] != other->trc[0] ||
+ trc[1] != other->trc[1] ||
+ trc[2] != other->trc[2])
return false;
return true;
}
/*!
- \fn bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
- \relates QColorSpace
-
- Returns \c true if colorspace \a colorSpace1 is not equal to colorspace \a colorSpace2;
- otherwise returns \c false
-*/
-
-/*!
Generates and returns a color space transformation from this color space to
\a colorspace.
*/
QColorTransform QColorSpace::transformationToColorSpace(const QColorSpace &colorspace) const
{
- if (!isValid() || !colorspace.isValid())
+ if (!isValid())
return QColorTransform();
- return d_ptr->transformationToColorSpace(colorspace.d_ptr);
+ if (*this == colorspace)
+ return QColorTransform();
+ if (!colorspace.isValidTarget()) {
+ qWarning() << "QColorSpace::transformationToColorSpace: colorspace not a valid target";
+ return QColorTransform();
+ }
+
+ return d_ptr->transformationToColorSpace(colorspace.d_ptr.get());
}
/*!
@@ -768,7 +1317,37 @@ QColorTransform QColorSpace::transformationToColorSpace(const QColorSpace &color
*/
QColorSpace::operator QVariant() const
{
- return QVariant(QMetaType::QColorSpace, this);
+ return QVariant::fromValue(*this);
+}
+
+/*!
+ Returns the name or short description. If a description hasn't been given
+ in setDescription(), the original name of the profile is returned if the
+ profile is unmodified, a guessed name is returned if the profile has been
+ recognized as a known color space, otherwise an empty string is returned.
+
+ \since 6.2
+*/
+QString QColorSpace::description() const noexcept
+{
+ if (d_ptr)
+ return d_ptr->userDescription.isEmpty() ? d_ptr->description : d_ptr->userDescription;
+ return QString();
+}
+
+/*!
+ Sets the name or short description of the color space to \a description.
+
+ If set to empty description() will return original or guessed descriptions
+ instead.
+
+ \since 6.2
+*/
+void QColorSpace::setDescription(const QString &description)
+{
+ detach();
+ d_ptr->iccProfile = {};
+ d_ptr->userDescription = description;
}
/*****************************************************************************
@@ -810,6 +1389,28 @@ QDataStream &operator>>(QDataStream &s, QColorSpace &colorSpace)
#endif // QT_NO_DATASTREAM
#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QColorSpacePrivate::TransferElement &)
+{
+ return dbg << ":Transfer";
+}
+QDebug operator<<(QDebug dbg, const QColorMatrix &)
+{
+ return dbg << ":Matrix";
+}
+QDebug operator<<(QDebug dbg, const QColorVector &)
+{
+ return dbg << ":Offset";
+}
+QDebug operator<<(QDebug dbg, const QColorCLUT &)
+{
+ return dbg << ":CLUT";
+}
+QDebug operator<<(QDebug dbg, const QList<QColorSpacePrivate::Element> &elements)
+{
+ for (auto &&element : elements)
+ std::visit([&](auto &&elm) { dbg << elm; }, element);
+ return dbg;
+}
QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
{
QDebugStateSaver saver(dbg);
@@ -818,8 +1419,22 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
if (colorSpace.d_ptr) {
if (colorSpace.d_ptr->namedColorSpace)
dbg << colorSpace.d_ptr->namedColorSpace << ", ";
- dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
- dbg << ", gamma=" << colorSpace.gamma();
+ if (!colorSpace.isValid()) {
+ dbg << "Invalid";
+ if (!colorSpace.d_ptr->iccProfile.isEmpty())
+ dbg << " with profile data";
+ } else if (colorSpace.d_ptr->isThreeComponentMatrix()) {
+ dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
+ dbg << ", gamma=" << colorSpace.gamma();
+ } else {
+ if (colorSpace.d_ptr->isPcsLab)
+ dbg << "PCSLab, ";
+ else
+ dbg << "PCSXYZ, ";
+ dbg << "A2B" << colorSpace.d_ptr->mAB;
+ if (!colorSpace.d_ptr->mBA.isEmpty())
+ dbg << ", B2A" << colorSpace.d_ptr->mBA;
+ }
}
dbg << ')';
return dbg;
@@ -827,3 +1442,5 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
#endif
QT_END_NAMESPACE
+
+#include "moc_qcolorspace.cpp"
diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h
index 08c9944301..488cbd6a53 100644
--- a/src/gui/painting/qcolorspace.h
+++ b/src/gui/painting/qcolorspace.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORSPACE_H
#define QCOLORSPACE_H
@@ -51,6 +15,8 @@ QT_BEGIN_NAMESPACE
class QColorSpacePrivate;
class QPointF;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QColorSpacePrivate, Q_GUI_EXPORT)
+
class Q_GUI_EXPORT QColorSpace
{
Q_GADGET
@@ -79,47 +45,87 @@ public:
ProPhotoRgb
};
Q_ENUM(TransferFunction)
+ enum class TransformModel : uint8_t {
+ ThreeComponentMatrix = 0,
+ ElementListProcessing,
+ };
+ Q_ENUM(TransformModel)
+ enum class ColorModel : uint8_t {
+ Undefined = 0,
+ Rgb = 1,
+ Gray = 2,
+ Cmyk = 3,
+ };
+ Q_ENUM(ColorModel)
- QColorSpace();
+ QColorSpace() noexcept = default;
QColorSpace(NamedColorSpace namedColorSpace);
- QColorSpace(Primaries primaries, TransferFunction fun, float gamma = 0.0f);
+ QColorSpace(const QPointF &whitePoint, TransferFunction transferFunction, float gamma = 0.0f);
+ QColorSpace(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable);
+ QColorSpace(Primaries primaries, TransferFunction transferFunction, float gamma = 0.0f);
QColorSpace(Primaries primaries, float gamma);
+ QColorSpace(Primaries primaries, const QList<uint16_t> &transferFunctionTable);
+ QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
+ const QPointF &greenPoint, const QPointF &bluePoint,
+ TransferFunction transferFunction, float gamma = 0.0f);
+ QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
+ const QPointF &greenPoint, const QPointF &bluePoint,
+ const QList<uint16_t> &transferFunctionTable);
QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint,
- TransferFunction fun, float gamma = 0.0f);
+ const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable);
~QColorSpace();
- QColorSpace(const QColorSpace &colorSpace);
- QColorSpace &operator=(const QColorSpace &colorSpace);
-
- QColorSpace(QColorSpace &&colorSpace) noexcept
- : d_ptr(qExchange(colorSpace.d_ptr, nullptr))
- { }
- QColorSpace &operator=(QColorSpace &&colorSpace) noexcept
+ QColorSpace(const QColorSpace &colorSpace) noexcept;
+ QColorSpace &operator=(const QColorSpace &colorSpace) noexcept
{
- // Make the deallocation of this->d_ptr happen in ~QColorSpace()
- QColorSpace(std::move(colorSpace)).swap(*this);
+ QColorSpace copy(colorSpace);
+ swap(copy);
return *this;
}
+ QColorSpace(QColorSpace &&colorSpace) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QColorSpace)
+
void swap(QColorSpace &colorSpace) noexcept
- { qSwap(d_ptr, colorSpace.d_ptr); }
+ { d_ptr.swap(colorSpace.d_ptr); }
Primaries primaries() const noexcept;
TransferFunction transferFunction() const noexcept;
float gamma() const noexcept;
+ QString description() const noexcept;
+ void setDescription(const QString &description);
+
void setTransferFunction(TransferFunction transferFunction, float gamma = 0.0f);
+ void setTransferFunction(const QList<uint16_t> &transferFunctionTable);
+ void setTransferFunctions(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable);
QColorSpace withTransferFunction(TransferFunction transferFunction, float gamma = 0.0f) const;
+ QColorSpace withTransferFunction(const QList<uint16_t> &transferFunctionTable) const;
+ QColorSpace withTransferFunctions(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable) const;
void setPrimaries(Primaries primariesId);
void setPrimaries(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint);
+ void setWhitePoint(const QPointF &whitePoint);
+ QPointF whitePoint() const;
+ TransformModel transformModel() const noexcept;
+ ColorModel colorModel() const noexcept;
+ void detach();
bool isValid() const noexcept;
+ bool isValidTarget() const noexcept;
- friend Q_GUI_EXPORT bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2);
- friend inline bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2);
+ friend inline bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
+ { return colorSpace1.equals(colorSpace2); }
+ friend inline bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
+ { return !(colorSpace1 == colorSpace2); }
static QColorSpace fromIccProfile(const QByteArray &iccProfile);
QByteArray iccProfile() const;
@@ -129,20 +135,16 @@ public:
operator QVariant() const;
private:
- Q_DECLARE_PRIVATE(QColorSpace)
- QColorSpacePrivate *d_ptr = nullptr;
+ friend class QColorSpacePrivate;
+ bool equals(const QColorSpace &other) const;
+
+ QExplicitlySharedDataPointer<QColorSpacePrivate> d_ptr;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace);
#endif
};
-bool Q_GUI_EXPORT operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2);
-inline bool operator!=(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
-{
- return !(colorSpace1 == colorSpace2);
-}
-
Q_DECLARE_SHARED(QColorSpace)
// QColorSpace stream functions
diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h
index e7add19ed3..4ec801b16b 100644
--- a/src/gui/painting/qcolorspace_p.h
+++ b/src/gui/painting/qcolorspace_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORSPACE_P_H
#define QCOLORSPACE_P_H
@@ -52,6 +16,7 @@
//
#include "qcolorspace.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolortrc_p.h"
#include "qcolortrclut_p.h"
@@ -60,6 +25,8 @@
#include <QtCore/qpoint.h>
#include <QtCore/qshareddata.h>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QColorSpacePrimaries
@@ -91,51 +58,76 @@ class QColorSpacePrivate : public QSharedData
public:
QColorSpacePrivate();
QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace);
- QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma);
- QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction fun, float gamma);
+ QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma);
+ QColorSpacePrivate(QColorSpace::Primaries primaries, const QList<uint16_t> &transferFunctionTable);
+ QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction transferFunction, float gamma);
+ QColorSpacePrivate(const QColorSpacePrimaries &primaries, const QList<uint16_t> &transferFunctionTable);
+ QColorSpacePrivate(const QColorSpacePrimaries &primaries,
+ const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueRransferFunctionTable);
+ QColorSpacePrivate(const QPointF &whitePoint, QColorSpace::TransferFunction transferFunction, float gamma);
+ QColorSpacePrivate(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable);
QColorSpacePrivate(const QColorSpacePrivate &other) = default;
- // named different from get to avoid accidental detachs
- static QColorSpacePrivate *getWritable(QColorSpace &colorSpace)
+ static const QColorSpacePrivate *get(const QColorSpace &colorSpace)
{
- if (!colorSpace.d_ptr) {
- colorSpace.d_ptr = new QColorSpacePrivate;
- colorSpace.d_ptr->ref.ref();
- } else if (colorSpace.d_ptr->ref.loadRelaxed() != 1) {
- colorSpace.d_ptr->ref.deref();
- colorSpace.d_ptr = new QColorSpacePrivate(*colorSpace.d_ptr);
- colorSpace.d_ptr->ref.ref();
- }
- Q_ASSERT(colorSpace.d_ptr->ref.loadRelaxed() == 1);
- return colorSpace.d_ptr;
+ return colorSpace.d_ptr.get();
}
- static const QColorSpacePrivate *get(const QColorSpace &colorSpace)
+ static QColorSpacePrivate *get(QColorSpace &colorSpace)
{
- return colorSpace.d_ptr;
+ return colorSpace.d_ptr.get();
}
+ bool equals(const QColorSpacePrivate *other) const;
+ bool isValid() const noexcept;
+
void initialize();
void setToXyzMatrix();
void setTransferFunction();
void identifyColorSpace();
+ void setTransferFunctionTable(const QList<uint16_t> &transferFunctionTable);
+ void setTransferFunctionTables(const QList<uint16_t> &redTransferFunctionTable,
+ const QList<uint16_t> &greenTransferFunctionTable,
+ const QList<uint16_t> &blueTransferFunctionTable);
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const;
+ QColorTransform transformationToXYZ() const;
+
+ bool isThreeComponentMatrix() const;
+ void clearElementListProcessingForEdit();
static constexpr QColorSpace::NamedColorSpace Unknown = QColorSpace::NamedColorSpace(0);
QColorSpace::NamedColorSpace namedColorSpace = Unknown;
QColorSpace::Primaries primaries = QColorSpace::Primaries::Custom;
QColorSpace::TransferFunction transferFunction = QColorSpace::TransferFunction::Custom;
+ QColorSpace::TransformModel transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
+ QColorSpace::ColorModel colorModel = QColorSpace::ColorModel::Undefined;
float gamma = 0.0f;
QColorVector whitePoint;
+ // Three component matrix data:
QColorTrc trc[3];
QColorMatrix toXyz;
-
+ QColorMatrix chad;
+
+ // Element list processing data:
+ struct TransferElement {
+ QColorTrc trc[4];
+ };
+ using Element = std::variant<TransferElement, QColorMatrix, QColorVector, QColorCLUT>;
+ bool isPcsLab = false;
+ // A = device, B = PCS
+ QList<Element> mAB, mBA;
+
+ // Metadata
QString description;
+ QString userDescription;
QByteArray iccProfile;
- static QBasicMutex s_lutWriteLock;
+ // Cached tables for three component matrix transform:
+ Q_CONSTINIT static QBasicMutex s_lutWriteLock;
struct LUT {
LUT() = default;
~LUT() = default;
@@ -148,9 +140,9 @@ public:
generated.storeRelaxed(1);
}
}
- QSharedPointer<QColorTrcLut> &operator[](int i) { return table[i]; }
- const QSharedPointer<QColorTrcLut> &operator[](int i) const { return table[i]; }
- QSharedPointer<QColorTrcLut> table[3];
+ std::shared_ptr<QColorTrcLut> &operator[](int i) { return table[i]; }
+ const std::shared_ptr<QColorTrcLut> &operator[](int i) const { return table[i]; }
+ std::shared_ptr<QColorTrcLut> table[3];
QAtomicInt generated;
} mutable lut;
};
diff --git a/src/gui/painting/qcolortransferfunction_p.h b/src/gui/painting/qcolortransferfunction_p.h
index 0575dbd888..484cc69114 100644
--- a/src/gui/painting/qcolortransferfunction_p.h
+++ b/src/gui/painting/qcolortransferfunction_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRANSFERFUNCTION_P_H
#define QCOLORTRANSFERFUNCTION_P_H
@@ -52,44 +16,52 @@
//
#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/QFlags>
#include <cmath>
QT_BEGIN_NAMESPACE
// Defines a ICC parametric curve type 4
-class Q_GUI_EXPORT QColorTransferFunction
+class QColorTransferFunction
{
public:
QColorTransferFunction() noexcept
- : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f), m_flags(0)
+ : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f)
+ , m_flags(Hints(Hint::Calculated) | Hint::IsGamma | Hint::IsIdentity)
{ }
+
QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g) noexcept
- : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(0)
+ : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags()
{ }
bool isGamma() const
{
updateHints();
- return m_flags & quint32(Hints::IsGamma);
+ return m_flags & Hint::IsGamma;
}
- bool isLinear() const
+ bool isIdentity() const
{
updateHints();
- return m_flags & quint32(Hints::IsLinear);
+ return m_flags & Hint::IsIdentity;
}
bool isSRgb() const
{
updateHints();
- return m_flags & quint32(Hints::IsSRgb);
+ return m_flags & Hint::IsSRgb;
}
float apply(float x) const
{
if (x < m_d)
return m_c * x + m_f;
+ float t = std::pow(m_a * x + m_b, m_g);
+ if (std::isfinite(t))
+ return t + m_e;
+ if (t > 0.f)
+ return 1.f;
else
- return std::pow(m_a * x + m_b, m_g) + m_e;
+ return 0.f;
}
QColorTransferFunction inverted() const
@@ -98,7 +70,7 @@ public:
d = m_c * m_d + m_f;
- if (!qFuzzyIsNull(m_c)) {
+ if (std::isnormal(m_c)) {
c = 1.0f / m_c;
f = -m_f / m_c;
} else {
@@ -106,8 +78,12 @@ public:
f = 0.0f;
}
- if (!qFuzzyIsNull(m_a) && !qFuzzyIsNull(m_g)) {
+ bool valid_abeg = std::isnormal(m_a) && std::isnormal(m_g);
+ if (valid_abeg)
a = std::pow(1.0f / m_a, m_g);
+ if (valid_abeg && !std::isfinite(a))
+ valid_abeg = false;
+ if (valid_abeg) {
b = -a * m_e;
e = -m_b / m_a;
g = 1.0f / m_g;
@@ -124,15 +100,19 @@ public:
// A few predefined curves:
static QColorTransferFunction fromGamma(float gamma)
{
- return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma);
+ return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma,
+ Hints(Hint::Calculated) | Hint::IsGamma |
+ (paramCompare(gamma, 1.0f) ? Hint::IsIdentity : Hint::NoHint));
}
static QColorTransferFunction fromSRgb()
{
- return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f);
+ return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f,
+ Hints(Hint::Calculated) | Hint::IsSRgb);
}
static QColorTransferFunction fromProPhotoRgb()
{
- return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f);
+ return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f,
+ Hints(Hint::Calculated));
}
bool matches(const QColorTransferFunction &o) const
{
@@ -152,7 +132,20 @@ public:
float m_f;
float m_g;
+ enum class Hint : quint32 {
+ NoHint = 0,
+ Calculated = 1,
+ IsGamma = 2,
+ IsIdentity = 4,
+ IsSRgb = 8
+ };
+
+ Q_DECLARE_FLAGS(Hints, Hint);
+
private:
+ QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g, Hints flags) noexcept
+ : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(flags)
+ { }
static inline bool paramCompare(float p1, float p2)
{
// Much fuzzier than fuzzy compare.
@@ -163,7 +156,7 @@ private:
void updateHints() const
{
- if (m_flags & quint32(Hints::Calculated))
+ if (m_flags & Hint::Calculated)
return;
// We do not consider the case with m_d = 1.0f linear or simple,
// since it wouldn't be linear for applyExtended().
@@ -171,24 +164,21 @@ private:
&& paramCompare(m_d, 0.0f)
&& paramCompare(m_e, 0.0f);
if (simple) {
- m_flags |= quint32(Hints::IsGamma);
+ m_flags |= Hint::IsGamma;
if (qFuzzyCompare(m_g, 1.0f))
- m_flags |= quint32(Hints::IsLinear);
+ m_flags |= Hint::IsIdentity;
} else {
if (*this == fromSRgb())
- m_flags |= quint32(Hints::IsSRgb);
+ m_flags |= Hint::IsSRgb;
}
- m_flags |= quint32(Hints::Calculated);
+ m_flags |= Hint::Calculated;
}
- enum class Hints : quint32 {
- Calculated = 1,
- IsGamma = 2,
- IsLinear = 4,
- IsSRgb = 8
- };
- mutable quint32 m_flags;
+
+ mutable Hints m_flags;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QColorTransferFunction::Hints);
+
inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2)
{
return f1.matches(f2);
diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h
index c945b55576..ce6ad0c4b2 100644
--- a/src/gui/painting/qcolortransfertable_p.h
+++ b/src/gui/painting/qcolortransfertable_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRANSFERTABLE_P_H
#define QCOLORTRANSFERTABLE_P_H
@@ -55,6 +19,8 @@
#include "qcolortransferfunction_p.h"
#include <QList>
+
+#include <algorithm>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -63,52 +29,85 @@ QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QColorTransferTable
{
public:
- QColorTransferTable() noexcept
- : m_tableSize(0)
- { }
- QColorTransferTable(uint32_t size, const QList<uint8_t> &table) noexcept
- : m_tableSize(size), m_table8(table)
- { }
- QColorTransferTable(uint32_t size, const QList<uint16_t> &table) noexcept
- : m_tableSize(size), m_table16(table)
- { }
-
- bool isValid() const
+ enum Type : uint8_t {
+ TwoWay = 0,
+ OneWay,
+ };
+ QColorTransferTable() noexcept = default;
+ QColorTransferTable(uint32_t size, const QList<uint8_t> &table, Type type = TwoWay) noexcept
+ : m_type(type), m_tableSize(size), m_table8(table)
{
- if (m_tableSize < 2)
+ Q_ASSERT(qsizetype(size) <= table.size());
+ }
+ QColorTransferTable(uint32_t size, const QList<uint16_t> &table, Type type = TwoWay) noexcept
+ : m_type(type), m_tableSize(size), m_table16(table)
+ {
+ Q_ASSERT(qsizetype(size) <= table.size());
+ }
+
+ bool isEmpty() const noexcept
+ {
+ return m_tableSize == 0;
+ }
+
+ bool isIdentity() const
+ {
+ if (isEmpty())
+ return true;
+ if (m_tableSize != 2)
return false;
+ if (!m_table8.isEmpty())
+ return m_table8[0] == 0 && m_table8[1] == 255;
+ return m_table16[0] == 0 && m_table16[1] == 65535;
+ }
-#if !defined(QT_NO_DEBUG)
- // The table must describe an injective curve:
+ bool checkValidity() const
+ {
+ if (isEmpty())
+ return true;
+ // Only one table can be set
+ if (!m_table8.isEmpty() && !m_table16.isEmpty())
+ return false;
+ // At least 2 elements
+ if (m_tableSize < 2)
+ return false;
+ return (m_type == OneWay) || checkInvertibility();
+ }
+ bool checkInvertibility() const
+ {
+ // The two-way tables must describe an injective curve:
if (!m_table8.isEmpty()) {
uint8_t val = 0;
for (uint i = 0; i < m_tableSize; ++i) {
- Q_ASSERT(m_table8[i] >= val);
+ if (m_table8[i] < val)
+ return false;
val = m_table8[i];
}
}
if (!m_table16.isEmpty()) {
uint16_t val = 0;
for (uint i = 0; i < m_tableSize; ++i) {
- Q_ASSERT(m_table16[i] >= val);
+ if (m_table16[i] < val)
+ return false;
val = m_table16[i];
}
}
-#endif
- return !m_table8.isEmpty() || !m_table16.isEmpty();
+ return true;
}
float apply(float x) const
{
- x = std::min(std::max(x, 0.0f), 1.0f);
+ if (isEmpty())
+ return x;
+ x = std::clamp(x, 0.0f, 1.0f);
x *= m_tableSize - 1;
- uint32_t lo = (int)std::floor(x);
- uint32_t hi = std::min(lo + 1, m_tableSize);
- float frac = x - lo;
+ const uint32_t lo = static_cast<uint32_t>(x);
+ const uint32_t hi = std::min(lo + 1, m_tableSize - 1);
+ const float frac = x - lo;
if (!m_table16.isEmpty())
- return (m_table16[lo] * (1.0f - frac) + m_table16[hi] * frac) * (1.0f/65535.0f);
+ return (m_table16[lo] + (m_table16[hi] - m_table16[lo]) * frac) * (1.0f/65535.0f);
if (!m_table8.isEmpty())
- return (m_table8[lo] * (1.0f - frac) + m_table8[hi] * frac) * (1.0f/255.0f);
+ return (m_table8[lo] + (m_table8[hi] - m_table8[lo]) * frac) * (1.0f/255.0f);
return x;
}
@@ -116,48 +115,27 @@ public:
float applyInverse(float x, float resultLargerThan = 0.0f) const
{
Q_ASSERT(resultLargerThan >= 0.0f && resultLargerThan <= 1.0f);
+ Q_ASSERT(m_type == TwoWay);
if (x <= 0.0f)
return 0.0f;
if (x >= 1.0f)
return 1.0f;
- if (!m_table16.isEmpty()) {
- float v = x * 65535.0f;
- uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
- for ( ; i < m_tableSize; ++i) {
- if (m_table16[i] > v)
- break;
- }
- if (i >= m_tableSize - 1)
- return 1.0f;
- float y1 = m_table16[i - 1];
- float y2 = m_table16[i];
- Q_ASSERT(x >= y1 && x < y2);
- float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
-
- }
- if (!m_table8.isEmpty()) {
- float v = x * 255.0f;
- uint i = std::floor(resultLargerThan * (m_tableSize - 1)) + 1;
- for ( ; i < m_tableSize; ++i) {
- if (m_table8[i] > v)
- break;
- }
- if (i >= m_tableSize - 1)
- return 1.0f;
- float y1 = m_table8[i - 1];
- float y2 = m_table8[i];
- Q_ASSERT(x >= y1 && x < y2);
- float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
- }
+ if (!m_table16.isEmpty())
+ return inverseLookup(x * 65535.0f, resultLargerThan, m_table16, m_tableSize - 1);
+ if (!m_table8.isEmpty())
+ return inverseLookup(x * 255.0f, resultLargerThan, m_table8, m_tableSize - 1);
return x;
}
bool asColorTransferFunction(QColorTransferFunction *transferFn)
{
- Q_ASSERT(isValid());
Q_ASSERT(transferFn);
+ if (isEmpty()) {
+ *transferFn = QColorTransferFunction();
+ return true;
+ }
+ if (m_tableSize < 2)
+ return false;
if (!m_table8.isEmpty() && (m_table8[0] != 0 || m_table8[m_tableSize - 1] != 255))
return false;
if (!m_table16.isEmpty() && (m_table16[0] != 0 || m_table16[m_tableSize - 1] != 65535))
@@ -205,27 +183,48 @@ public:
friend inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2);
friend inline bool operator==(const QColorTransferTable &t1, const QColorTransferTable &t2);
- uint32_t m_tableSize;
+ Type m_type = TwoWay;
+ uint32_t m_tableSize = 0;
QList<uint8_t> m_table8;
QList<uint16_t> m_table16;
+private:
+ template<typename T>
+ static float inverseLookup(float needle, float resultLargerThan, const QList<T> &table, quint32 tableMax)
+ {
+ uint32_t i = static_cast<uint32_t>(resultLargerThan * tableMax);
+ auto it = std::lower_bound(table.cbegin() + i, table.cend(), needle);
+ i = it - table.cbegin();
+ if (i == 0)
+ return 0.0f;
+ if (i >= tableMax)
+ return 1.0f;
+ const float y1 = table[i - 1];
+ const float y2 = table[i];
+ Q_ASSERT(needle >= y1 && needle <= y2);
+ const float fr = (needle - y1) / (y2 - y1);
+ return (i + fr) * (1.0f / tableMax);
+ }
+
};
inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2)
{
if (t1.m_tableSize != t2.m_tableSize)
return true;
+ if (t1.m_type != t2.m_type)
+ return true;
if (t1.m_table8.isEmpty() != t2.m_table8.isEmpty())
return true;
if (t1.m_table16.isEmpty() != t2.m_table16.isEmpty())
return true;
if (!t1.m_table8.isEmpty()) {
- for (quint32 i = 0; i < t1.m_tableSize; ++i) {
+ for (uint32_t i = 0; i < t1.m_tableSize; ++i) {
if (t1.m_table8[i] != t2.m_table8[i])
return true;
}
}
if (!t1.m_table16.isEmpty()) {
- for (quint32 i = 0; i < t1.m_tableSize; ++i) {
+ for (uint32_t i = 0; i < t1.m_tableSize; ++i) {
if (t1.m_table16[i] != t2.m_table16[i])
return true;
}
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index 10ccefed74..aac07bdc09 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcolortransform.h"
#include "qcolortransform_p.h"
+#include "qcmyk_p.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolorspace_p.h"
#include "qcolortrc_p.h"
@@ -49,6 +14,7 @@
#include <QtCore/qatomic.h>
#include <QtCore/qmath.h>
#include <QtGui/qcolor.h>
+#include <QtGui/qimage.h>
#include <QtGui/qtransform.h>
#include <QtCore/private/qsimd_p.h>
@@ -56,7 +22,7 @@
QT_BEGIN_NAMESPACE
-QColorTrcLut *lutFromTrc(const QColorTrc &trc)
+std::shared_ptr<QColorTrcLut> lutFromTrc(const QColorTrc &trc)
{
if (trc.m_type == QColorTrc::Type::Table)
return QColorTrcLut::fromTransferTable(trc.m_table);
@@ -80,12 +46,12 @@ void QColorTransformPrivate::updateLutsIn() const
}
if (colorSpaceIn->trc[0] == colorSpaceIn->trc[1] && colorSpaceIn->trc[0] == colorSpaceIn->trc[2]) {
- colorSpaceIn->lut[0].reset(lutFromTrc(colorSpaceIn->trc[0]));
+ colorSpaceIn->lut[0] = lutFromTrc(colorSpaceIn->trc[0]);
colorSpaceIn->lut[1] = colorSpaceIn->lut[0];
colorSpaceIn->lut[2] = colorSpaceIn->lut[0];
} else {
for (int i = 0; i < 3; ++i)
- colorSpaceIn->lut[i].reset(lutFromTrc(colorSpaceIn->trc[i]));
+ colorSpaceIn->lut[i] = lutFromTrc(colorSpaceIn->trc[i]);
}
colorSpaceIn->lut.generated.storeRelease(1);
@@ -104,12 +70,12 @@ void QColorTransformPrivate::updateLutsOut() const
}
if (colorSpaceOut->trc[0] == colorSpaceOut->trc[1] && colorSpaceOut->trc[0] == colorSpaceOut->trc[2]) {
- colorSpaceOut->lut[0].reset(lutFromTrc(colorSpaceOut->trc[0]));
+ colorSpaceOut->lut[0] = lutFromTrc(colorSpaceOut->trc[0]);
colorSpaceOut->lut[1] = colorSpaceOut->lut[0];
colorSpaceOut->lut[2] = colorSpaceOut->lut[0];
} else {
for (int i = 0; i < 3; ++i)
- colorSpaceOut->lut[i].reset(lutFromTrc(colorSpaceOut->trc[i]));
+ colorSpaceOut->lut[i] = lutFromTrc(colorSpaceOut->trc[i]);
}
colorSpaceOut->lut.generated.storeRelease(1);
@@ -134,18 +100,74 @@ void QColorTransformPrivate::updateLutsOut() const
*/
-QColorTransform::QColorTransform(const QColorTransform &colorTransform) noexcept
- : d(colorTransform.d)
+QColorTransform::QColorTransform(const QColorTransform &colorTransform) noexcept = default;
+
+QColorTransform::~QColorTransform() = default;
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QColorTransformPrivate)
+
+/*!
+ \since 6.4
+ Returns true if the color transform is the identity transform.
+*/
+bool QColorTransform::isIdentity() const noexcept
{
- if (d)
- d->ref.ref();
+ return !d || d->isIdentity();
}
+/*!
+ \fn bool QColorTransform::operator==(const QColorTransform &ct1, const QColorTransform &ct2)
+ \since 6.4
+ Returns true if \a ct1 defines the same color transformation as \a ct2.
+*/
+
+/*!
+ \fn bool QColorTransform::operator!=(const QColorTransform &ct1, const QColorTransform &ct2)
+ \since 6.4
+ Returns true if \a ct1 does not define the same transformation as \a ct2.
+*/
-QColorTransform::~QColorTransform()
+/*! \internal
+*/
+bool QColorTransform::compare(const QColorTransform &other) const
{
- if (d && !d->ref.deref())
- delete d;
+ if (d == other.d)
+ return true;
+ if (bool(d) != bool(other.d))
+ return d ? d->isIdentity() : other.d->isIdentity();
+ if (d->colorMatrix != other.d->colorMatrix)
+ return false;
+ if (bool(d->colorSpaceIn) != bool(other.d->colorSpaceIn))
+ return false;
+ if (bool(d->colorSpaceOut) != bool(other.d->colorSpaceOut))
+ return false;
+ if (d->colorSpaceIn) {
+ if (d->colorSpaceIn->transformModel != other.d->colorSpaceIn->transformModel)
+ return false;
+ if (d->colorSpaceIn->isThreeComponentMatrix()) {
+ for (int i = 0; i < 3; ++i) {
+ if (d->colorSpaceIn && d->colorSpaceIn->trc[i] != other.d->colorSpaceIn->trc[i])
+ return false;
+ }
+ } else {
+ if (!d->colorSpaceIn->equals(other.d->colorSpaceIn.constData()))
+ return false;
+ }
+ }
+ if (d->colorSpaceOut) {
+ if (d->colorSpaceOut->transformModel != other.d->colorSpaceOut->transformModel)
+ return false;
+ if (d->colorSpaceOut->isThreeComponentMatrix()) {
+ for (int i = 0; i < 3; ++i) {
+ if (d->colorSpaceOut && d->colorSpaceOut->trc[i] != other.d->colorSpaceOut->trc[i])
+ return false;
+ }
+ } else {
+ if (!d->colorSpaceOut->equals(other.d->colorSpaceOut.constData()))
+ return false;
+ }
+ }
+ return true;
}
/*!
@@ -159,23 +181,7 @@ QRgb QColorTransform::map(QRgb argb) const
return argb;
constexpr float f = 1.0f / 255.0f;
QColorVector c = { qRed(argb) * f, qGreen(argb) * f, qBlue(argb) * f };
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- c = d->colorMatrix.map(c);
- c.x = std::max(0.0f, std::min(1.0f, c.x));
- c.y = std::max(0.0f, std::min(1.0f, c.y));
- c.z = std::max(0.0f, std::min(1.0f, c.z));
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
-
+ c = d->map(c);
return qRgba(c.x * 255 + 0.5f, c.y * 255 + 0.5f, c.z * 255 + 0.5f, qAlpha(argb));
}
@@ -190,24 +196,44 @@ QRgba64 QColorTransform::map(QRgba64 rgba64) const
return rgba64;
constexpr float f = 1.0f / 65535.0f;
QColorVector c = { rgba64.red() * f, rgba64.green() * f, rgba64.blue() * f };
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- c = d->colorMatrix.map(c);
- c.x = std::max(0.0f, std::min(1.0f, c.x));
- c.y = std::max(0.0f, std::min(1.0f, c.y));
- c.z = std::max(0.0f, std::min(1.0f, c.z));
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
+ c = d->map(c);
+ return QRgba64::fromRgba64(c.x * 65535.f + 0.5f, c.y * 65535.f + 0.5f, c.z * 65535.f + 0.5f, rgba64.alpha());
+}
+
+/*!
+ Applies the color transformation on the QRgbaFloat16 value \a rgbafp16.
+
+ The input should be opaque or unpremultiplied.
+ \since 6.4
+*/
+QRgbaFloat16 QColorTransform::map(QRgbaFloat16 rgbafp16) const
+{
+ if (!d)
+ return rgbafp16;
+ QColorVector c(rgbafp16.r, rgbafp16.g, rgbafp16.b);
+ c = d->mapExtended(c);
+ rgbafp16.r = qfloat16(c.x);
+ rgbafp16.g = qfloat16(c.y);
+ rgbafp16.b = qfloat16(c.z);
+ return rgbafp16;
+}
- return QRgba64::fromRgba64(c.x * 65535, c.y * 65535, c.z * 65535, rgba64.alpha());
+/*!
+ Applies the color transformation on the QRgbaFloat32 value \a rgbafp32.
+
+ The input should be opaque or unpremultiplied.
+ \since 6.4
+*/
+QRgbaFloat32 QColorTransform::map(QRgbaFloat32 rgbafp32) const
+{
+ if (!d)
+ return rgbafp32;
+ QColorVector c(rgbafp32.r, rgbafp32.g, rgbafp32.b);
+ c = d->mapExtended(c);
+ rgbafp32.r = c.x;
+ rgbafp32.g = c.y;
+ rgbafp32.b = c.z;
+ return rgbafp32;
}
/*!
@@ -219,43 +245,42 @@ QColor QColorTransform::map(const QColor &color) const
if (!d)
return color;
QColor clr = color;
- if (color.spec() != QColor::ExtendedRgb || color.spec() != QColor::Rgb)
- clr = clr.toRgb();
-
- QColorVector c = { (float)clr.redF(), (float)clr.greenF(), (float)clr.blueF() };
- if (clr.spec() == QColor::ExtendedRgb) {
- c.x = d->colorSpaceIn->trc[0].applyExtended(c.x);
- c.y = d->colorSpaceIn->trc[1].applyExtended(c.y);
- c.z = d->colorSpaceIn->trc[2].applyExtended(c.z);
- } else {
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- }
- c = d->colorMatrix.map(c);
- bool inGamut = c.x >= 0.0f && c.x <= 1.0f && c.y >= 0.0f && c.y <= 1.0f && c.z >= 0.0f && c.z <= 1.0f;
- if (inGamut) {
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverseExtended(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverseExtended(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverseExtended(c.z);
+ if (d->colorSpaceIn->colorModel == QColorSpace::ColorModel::Rgb) {
+ if (color.spec() != QColor::ExtendedRgb && color.spec() != QColor::Rgb)
+ clr = clr.toRgb();
+ } else if (d->colorSpaceIn->colorModel == QColorSpace::ColorModel::Cmyk) {
+ if (color.spec() != QColor::Cmyk)
+ clr = clr.toCmyk();
}
+
+ QColorVector c =
+ (clr.spec() == QColor::Cmyk)
+ ? QColorVector(clr.cyanF(), clr.magentaF(), clr.yellowF(), clr.blackF())
+ : QColorVector(clr.redF(), clr.greenF(), clr.blueF());
+
+ c = d->mapExtended(c);
+
QColor out;
- out.setRgbF(c.x, c.y, c.z, color.alphaF());
+ if (d->colorSpaceOut->colorModel == QColorSpace::ColorModel::Cmyk) {
+ c.x = std::clamp(c.x, 0.f, 1.f);
+ c.y = std::clamp(c.y, 0.f, 1.f);
+ c.z = std::clamp(c.z, 0.f, 1.f);
+ c.w = std::clamp(c.w, 0.f, 1.f);
+ out.setCmykF(c.x, c.y, c.z, c.w, color.alphaF());
+ } else {
+ out.setRgbF(c.x, c.y, c.z, color.alphaF());
+ }
return out;
}
// Optimized sub-routines for fast block based conversion:
+enum ApplyMatrixForm {
+ DoNotClamp = 0,
+ DoClamp = 1
+};
+
+template<ApplyMatrixForm doClamp = DoClamp>
static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorMatrix &colorMatrix)
{
#if defined(__SSE2__)
@@ -275,20 +300,117 @@ static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorM
cx = _mm_add_ps(cx, cy);
cx = _mm_add_ps(cx, cz);
// Clamp:
- cx = _mm_min_ps(cx, maxV);
- cx = _mm_max_ps(cx, minV);
+ if (doClamp) {
+ cx = _mm_min_ps(cx, maxV);
+ cx = _mm_max_ps(cx, minV);
+ }
_mm_storeu_ps(&buffer[j].x, cx);
}
+#elif defined(__ARM_NEON__)
+ const float32x4_t minV = vdupq_n_f32(0.0f);
+ const float32x4_t maxV = vdupq_n_f32(1.0f);
+ const float32x4_t xMat = vld1q_f32(&colorMatrix.r.x);
+ const float32x4_t yMat = vld1q_f32(&colorMatrix.g.x);
+ const float32x4_t zMat = vld1q_f32(&colorMatrix.b.x);
+ for (qsizetype j = 0; j < len; ++j) {
+ float32x4_t c = vld1q_f32(&buffer[j].x);
+ float32x4_t cx = vmulq_n_f32(xMat, vgetq_lane_f32(c, 0));
+ float32x4_t cy = vmulq_n_f32(yMat, vgetq_lane_f32(c, 1));
+ float32x4_t cz = vmulq_n_f32(zMat, vgetq_lane_f32(c, 2));
+ cx = vaddq_f32(cx, cy);
+ cx = vaddq_f32(cx, cz);
+ // Clamp:
+ if (doClamp) {
+ cx = vminq_f32(cx, maxV);
+ cx = vmaxq_f32(cx, minV);
+ }
+ vst1q_f32(&buffer[j].x, cx);
+ }
#else
- for (int j = 0; j < len; ++j) {
+ for (qsizetype j = 0; j < len; ++j) {
const QColorVector cv = colorMatrix.map(buffer[j]);
- buffer[j].x = std::max(0.0f, std::min(1.0f, cv.x));
- buffer[j].y = std::max(0.0f, std::min(1.0f, cv.y));
- buffer[j].z = std::max(0.0f, std::min(1.0f, cv.z));
+ if (doClamp) {
+ buffer[j].x = std::clamp(cv.x, 0.f, 1.f);
+ buffer[j].y = std::clamp(cv.y, 0.f, 1.f);
+ buffer[j].z = std::clamp(cv.z, 0.f, 1.f);
+ } else {
+ buffer[j] = cv;
+ }
}
#endif
}
+template<ApplyMatrixForm doClamp = DoClamp>
+static void clampIfNeeded(QColorVector *buffer, const qsizetype len)
+{
+ if constexpr (doClamp != DoClamp)
+ return;
+#if defined(__SSE2__)
+ const __m128 minV = _mm_set1_ps(0.0f);
+ const __m128 maxV = _mm_set1_ps(1.0f);
+ for (qsizetype j = 0; j < len; ++j) {
+ __m128 c = _mm_loadu_ps(&buffer[j].x);
+ c = _mm_min_ps(c, maxV);
+ c = _mm_max_ps(c, minV);
+ _mm_storeu_ps(&buffer[j].x, c);
+ }
+#elif defined(__ARM_NEON__)
+ const float32x4_t minV = vdupq_n_f32(0.0f);
+ const float32x4_t maxV = vdupq_n_f32(1.0f);
+ for (qsizetype j = 0; j < len; ++j) {
+ float32x4_t c = vld1q_f32(&buffer[j].x);
+ c = vminq_f32(c, maxV);
+ c = vmaxq_f32(c, minV);
+ vst1q_f32(&buffer[j].x, c);
+ }
+#else
+ for (qsizetype j = 0; j < len; ++j) {
+ const QColorVector cv = buffer[j];
+ buffer[j].x = std::clamp(cv.x, 0.f, 1.f);
+ buffer[j].y = std::clamp(cv.y, 0.f, 1.f);
+ buffer[j].z = std::clamp(cv.z, 0.f, 1.f);
+ }
+#endif
+}
+
+#if defined(__SSE2__) || defined(__ARM_NEON__)
+template<typename T>
+static constexpr inline bool isArgb();
+template<>
+constexpr inline bool isArgb<QRgb>() { return true; }
+template<>
+constexpr inline bool isArgb<QRgba64>() { return false; }
+
+template<typename T>
+static inline int getAlpha(const T &p);
+template<>
+inline int getAlpha<QRgb>(const QRgb &p)
+{ return qAlpha(p); }
+template<>
+inline int getAlpha<QRgba64>(const QRgba64 &p)
+{ return p.alpha(); }
+
+#endif
+
+template<typename T>
+static float getAlphaF(const T &);
+template<> float getAlphaF(const QRgb &r)
+{
+ return qAlpha(r) * (1.f / 255.f);
+}
+template<> float getAlphaF(const QCmyk32 &)
+{
+ return 1.f;
+}
+template<> float getAlphaF(const QRgba64 &r)
+{
+ return r.alpha() * (1.f / 65535.f);
+}
+template<> float getAlphaF(const QRgbaFloat32 &r)
+{
+ return r.a;
+}
+
template<typename T>
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr);
template<typename T>
@@ -320,15 +442,14 @@ inline void loadP<QRgba64>(const QRgba64 &p, __m128i &v)
#else
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
#endif
- // Shuffle to ARGB as the template below expects it
- v = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 0, 1, 2));
}
template<typename T>
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
+ constexpr bool isARGB = isArgb<T>();
for (qsizetype i = 0; i < len; ++i) {
__m128i v;
loadP<T>(src[i], v);
@@ -345,10 +466,10 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
vf = _mm_andnot_ps(vAlphaMask, vf);
// LUT
- v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
- const int ridx = _mm_extract_epi16(v, 4);
+ v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
- const int bidx = _mm_extract_epi16(v, 0);
+ const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
@@ -358,7 +479,51 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
}
}
-// Load to [0-4080] in 4x32 SIMD
+template<>
+void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
+ const __m128 vZero = _mm_set1_ps(0.0f);
+ const __m128 vOne = _mm_set1_ps(1.0f);
+ for (qsizetype i = 0; i < len; ++i) {
+ __m128 vf = _mm_loadu_ps(&src[i].r);
+ // Approximate 1/a:
+ __m128 va = _mm_shuffle_ps(vf, vf, _MM_SHUFFLE(3, 3, 3, 3));
+ __m128 via = _mm_rcp_ps(va);
+ via = _mm_sub_ps(_mm_add_ps(via, via), _mm_mul_ps(via, _mm_mul_ps(via, va)));
+ // v * (1/a)
+ vf = _mm_mul_ps(vf, via);
+
+ // Handle zero alpha
+ __m128 vAlphaMask = _mm_cmpeq_ps(va, vZero);
+ vf = _mm_andnot_ps(vAlphaMask, vf);
+
+ // LUT
+ const __m128 under = _mm_cmplt_ps(vf, vZero);
+ const __m128 over = _mm_cmpgt_ps(vf, vOne);
+ if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
+ // Within gamut
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = _mm_extract_epi16(v, 0);
+ const int gidx = _mm_extract_epi16(v, 2);
+ const int bidx = _mm_extract_epi16(v, 4);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
+ vf = _mm_mul_ps(_mm_cvtepi32_ps(v), viFF00);
+ _mm_storeu_ps(&buffer[i].x, vf);
+ } else {
+ // Outside 0.0->1.0 gamut
+ _mm_storeu_ps(&buffer[i].x, vf);
+ buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(buffer[i].x);
+ buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(buffer[i].y);
+ buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(buffer[i].z);
+ }
+ }
+}
+
+// Load to [0->TrcResolution] in 4x32 SIMD
template<typename T>
static inline void loadPU(const T &p, __m128i &v);
@@ -372,7 +537,7 @@ inline void loadPU<QRgb>(const QRgb &p, __m128i &v)
v = _mm_unpacklo_epi8(v, _mm_setzero_si128());
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
#endif
- v = _mm_slli_epi32(v, 4);
+ v = _mm_slli_epi32(v, QColorTrcLut::ShiftUp);
}
template<>
@@ -385,21 +550,20 @@ inline void loadPU<QRgba64>(const QRgba64 &p, __m128i &v)
#else
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
#endif
- v = _mm_srli_epi32(v, 4);
- // Shuffle to ARGB as the template below expects it
- v = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 0, 1, 2));
+ v = _mm_srli_epi32(v, QColorTrcLut::ShiftDown);
}
template<typename T>
void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
+ constexpr bool isARGB = isArgb<T>();
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
for (qsizetype i = 0; i < len; ++i) {
__m128i v;
loadPU<T>(src[i], v);
- const int ridx = _mm_extract_epi16(v, 4);
+ const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
- const int bidx = _mm_extract_epi16(v, 0);
+ const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
@@ -408,6 +572,131 @@ void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len
}
}
+template<>
+void loadUnpremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
+ const __m128 vZero = _mm_set1_ps(0.0f);
+ const __m128 vOne = _mm_set1_ps(1.0f);
+ for (qsizetype i = 0; i < len; ++i) {
+ __m128 vf = _mm_loadu_ps(&src[i].r);
+ const __m128 under = _mm_cmplt_ps(vf, vZero);
+ const __m128 over = _mm_cmpgt_ps(vf, vOne);
+ if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
+ // Within gamut
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = _mm_extract_epi16(v, 0);
+ const int gidx = _mm_extract_epi16(v, 2);
+ const int bidx = _mm_extract_epi16(v, 4);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
+ vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00);
+ _mm_storeu_ps(&buffer[i].x, vf);
+ } else {
+ // Outside 0.0->1.0 gamut
+ buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(src[i].r);
+ buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(src[i].g);
+ buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(src[i].b);
+ }
+ }
+}
+
+#elif defined(__ARM_NEON__)
+// Load to [0-alpha] in 4x32 SIMD
+template<typename T>
+static inline void loadP(const T &p, uint32x4_t &v);
+
+template<>
+inline void loadP<QRgb>(const QRgb &p, uint32x4_t &v)
+{
+ v = vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_u32(vmov_n_u32(p)))));
+}
+
+template<>
+inline void loadP<QRgba64>(const QRgba64 &p, uint32x4_t &v)
+{
+ v = vmovl_u16(vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&p))));
+}
+
+template<typename T>
+static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ constexpr bool isARGB = isArgb<T>();
+ const float iFF00 = 1.0f / (255 * 256);
+ for (qsizetype i = 0; i < len; ++i) {
+ uint32x4_t v;
+ loadP<T>(src[i], v);
+ float32x4_t vf = vcvtq_f32_u32(v);
+ // Approximate 1/a:
+ float32x4_t va = vdupq_n_f32(vgetq_lane_f32(vf, 3));
+ float32x4_t via = vrecpeq_f32(va); // estimate 1/a
+ via = vmulq_f32(vrecpsq_f32(va, via), via);
+
+ // v * (1/a)
+ vf = vmulq_f32(vf, via);
+
+ // Handle zero alpha
+#if defined(Q_PROCESSOR_ARM_64)
+ uint32x4_t vAlphaMask = vceqzq_f32(va);
+#else
+ uint32x4_t vAlphaMask = vceqq_f32(va, vdupq_n_f32(0.0));
+#endif
+ vf = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(vf), vAlphaMask));
+
+ // LUT
+ v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f)));
+ const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
+ const int gidx = vgetq_lane_u32(v, 1);
+ const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
+ vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
+
+ vst1q_f32(&buffer[i].x, vf);
+ }
+}
+
+// Load to [0->TrcResultion] in 4x32 SIMD
+template<typename T>
+static inline void loadPU(const T &p, uint32x4_t &v);
+
+template<>
+inline void loadPU<QRgb>(const QRgb &p, uint32x4_t &v)
+{
+ v = vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_u32(vmov_n_u32(p)))));
+ v = vshlq_n_u32(v, QColorTrcLut::ShiftUp);
+}
+
+template<>
+inline void loadPU<QRgba64>(const QRgba64 &p, uint32x4_t &v)
+{
+ uint16x4_t v16 = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&p)));
+ v16 = vsub_u16(v16, vshr_n_u16(v16, 8));
+ v = vmovl_u16(v16);
+ v = vshrq_n_u32(v, QColorTrcLut::ShiftDown);
+}
+
+template<typename T>
+void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ constexpr bool isARGB = isArgb<T>();
+ const float iFF00 = 1.0f / (255 * 256);
+ for (qsizetype i = 0; i < len; ++i) {
+ uint32x4_t v;
+ loadPU<T>(src[i], v);
+ const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
+ const int gidx = vgetq_lane_u32(v, 1);
+ const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
+ v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
+ float32x4_t vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
+ vst1q_f32(&buffer[i].x, vf);
+ }
+}
#else
template<>
void loadPremultiplied<QRgb>(QColorVector *buffer, const QRgb *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
@@ -416,7 +705,7 @@ void loadPremultiplied<QRgb>(QColorVector *buffer, const QRgb *src, const qsizet
const uint p = src[i];
const int a = qAlpha(p);
if (a) {
- const float ia = 4080.0f / a;
+ const float ia = float(QColorTrcLut::Resolution) / a;
const int ridx = int(qRed(p) * ia + 0.5f);
const int gidx = int(qGreen(p) * ia + 0.5f);
const int bidx = int(qBlue(p) * ia + 0.5f);
@@ -436,7 +725,7 @@ void loadPremultiplied<QRgba64>(QColorVector *buffer, const QRgba64 *src, const
const QRgba64 &p = src[i];
const int a = p.alpha();
if (a) {
- const float ia = 4080.0f / a;
+ const float ia = float(QColorTrcLut::Resolution) / a;
const int ridx = int(p.red() * ia + 0.5f);
const int gidx = int(p.green() * ia + 0.5f);
const int bidx = int(p.blue() * ia + 0.5f);
@@ -471,137 +760,416 @@ void loadUnpremultiplied<QRgba64>(QColorVector *buffer, const QRgba64 *src, cons
}
}
#endif
+#if !defined(__SSE2__)
+template<>
+void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const QRgbaFloat32 &p = src[i];
+ const float a = p.a;
+ if (a) {
+ const float ia = 1.0f / a;
+ buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(p.r * ia);
+ buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(p.g * ia);
+ buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(p.b * ia);
+ } else {
+ buffer[i].x = buffer[i].y = buffer[i].z = 0.0f;
+ }
+ }
+}
-static void storePremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
- const QColorTransformPrivate *d_ptr)
+template<>
+void loadUnpremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
+ for (qsizetype i = 0; i < len; ++i) {
+ const QRgbaFloat32 &p = src[i];
+ buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(p.r);
+ buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(p.g);
+ buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(p.b);
+ }
+}
+#endif
+
#if defined(__SSE2__)
- const __m128 v4080 = _mm_set1_ps(4080.f);
+template<typename T>
+static inline void storeP(T &p, __m128i &v, int a);
+template<>
+inline void storeP<QRgb>(QRgb &p, __m128i &v, int a)
+{
+ v = _mm_packs_epi32(v, v);
+ v = _mm_insert_epi16(v, a, 3);
+ p = _mm_cvtsi128_si32(_mm_packus_epi16(v, v));
+}
+template<>
+inline void storeP<QRgba64>(QRgba64 &p, __m128i &v, int a)
+{
+#if defined(__SSE4_1__)
+ v = _mm_packus_epi32(v, v);
+ v = _mm_insert_epi16(v, a, 3);
+ _mm_storel_epi64((__m128i *)&p, v);
+#else
+ const int r = _mm_extract_epi16(v, 0);
+ const int g = _mm_extract_epi16(v, 2);
+ const int b = _mm_extract_epi16(v, 4);
+ p = qRgba64(r, g, b, a);
+#endif
+}
+
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = qAlpha(src[i]);
+ const int a = getAlpha<S>(src[i]);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
- __m128 va = _mm_set1_ps(a);
- va = _mm_mul_ps(va, iFF00);
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ __m128 va = _mm_mul_ps(_mm_set1_ps(a), iFF00);
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 4);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], isARGB ? 4 : 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 2);
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], isARGB ? 0 : 4);
vf = _mm_cvtepi32_ps(v);
vf = _mm_mul_ps(vf, va);
v = _mm_cvtps_epi32(vf);
- v = _mm_packs_epi32(v, v);
- v = _mm_insert_epi16(v, a, 3);
- v = _mm_packus_epi16(v, v);
- dst[i] = _mm_cvtsi128_si32(v);
+ storeP<D>(dst[i], v, a);
}
-#else
+}
+
+template<typename S>
+static void storePremultiplied(QRgbaFloat32 *dst, const S *src,
+ const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ const __m128 vZero = _mm_set1_ps(0.0f);
+ const __m128 vOne = _mm_set1_ps(1.0f);
+ const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
for (qsizetype i = 0; i < len; ++i) {
- const int a = qAlpha(src[i]);
- const float fa = a / (255.0f * 256.0f);
- const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)];
- const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)];
- const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)];
- dst[i] = qRgba(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a);
+ const float a = getAlphaF<S>(src[i]);
+ __m128 va = _mm_set1_ps(a);
+ __m128 vf = _mm_loadu_ps(&buffer[i].x);
+ const __m128 under = _mm_cmplt_ps(vf, vZero);
+ const __m128 over = _mm_cmpgt_ps(vf, vOne);
+ if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
+ // Within gamut
+ va = _mm_mul_ps(va, viFF00);
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = _mm_extract_epi16(v, 0);
+ const int gidx = _mm_extract_epi16(v, 2);
+ const int bidx = _mm_extract_epi16(v, 4);
+ v = _mm_setzero_si128();
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 4);
+ vf = _mm_mul_ps(_mm_cvtepi32_ps(v), va);
+ _mm_store_ps(&dst[i].r, vf);
+ } else {
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
+ vf = _mm_mul_ps(_mm_load_ps(&dst[i].r), va);
+ _mm_store_ps(&dst[i].r, vf);
+ }
+ dst[i].a = a;
}
-#endif
}
-static void storeUnpremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+template<typename T>
+static inline void storePU(T &p, __m128i &v, int a);
+template<>
+inline void storePU<QRgb>(QRgb &p, __m128i &v, int a)
+{
+ v = _mm_add_epi16(v, _mm_set1_epi16(0x80));
+ v = _mm_srli_epi16(v, 8);
+ v = _mm_insert_epi16(v, a, 3);
+ p = _mm_cvtsi128_si32(_mm_packus_epi16(v, v));
+}
+template<>
+inline void storePU<QRgba64>(QRgba64 &p, __m128i &v, int a)
+{
+ v = _mm_add_epi16(v, _mm_srli_epi16(v, 8));
+ v = _mm_insert_epi16(v, a, 3);
+ _mm_storel_epi64((__m128i *)&p, v);
+}
+
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
-#if defined(__SSE2__)
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = qAlpha(src[i]);
+ const int a = getAlpha<S>(src[i]);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
v = _mm_setzero_si128();
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], isARGB ? 2 : 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 1);
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0);
- v = _mm_add_epi16(v, _mm_set1_epi16(0x80));
- v = _mm_srli_epi16(v, 8);
- v = _mm_insert_epi16(v, a, 3);
- v = _mm_packus_epi16(v, v);
- dst[i] = _mm_cvtsi128_si32(v);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], isARGB ? 0 : 2);
+ storePU<D>(dst[i], v, a);
}
-#else
+}
+
+template<typename S>
+void storeUnpremultiplied(QRgbaFloat32 *dst, const S *src,
+ const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ const __m128 vZero = _mm_set1_ps(0.0f);
+ const __m128 vOne = _mm_set1_ps(1.0f);
+ const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
for (qsizetype i = 0; i < len; ++i) {
- const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x);
- const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y);
- const int b = d_ptr->colorSpaceOut->lut[2]->u8FromLinearF32(buffer[i].z);
- dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ const float a = getAlphaF<S>(src[i]);
+ __m128 vf = _mm_loadu_ps(&buffer[i].x);
+ const __m128 under = _mm_cmplt_ps(vf, vZero);
+ const __m128 over = _mm_cmpgt_ps(vf, vOne);
+ if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
+ // Within gamut
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = _mm_extract_epi16(v, 0);
+ const int gidx = _mm_extract_epi16(v, 2);
+ const int bidx = _mm_extract_epi16(v, 4);
+ v = _mm_setzero_si128();
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 4);
+ vf = _mm_mul_ps(_mm_cvtepi32_ps(v), viFF00);
+ _mm_storeu_ps(&dst[i].r, vf);
+ } else {
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
+ }
+ dst[i].a = a;
}
-#endif
}
-static void storeOpaque(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+template<typename T>
+static void storeOpaque(T *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
-#if defined(__SSE2__)
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ constexpr bool isARGB = isArgb<T>();
for (qsizetype i = 0; i < len; ++i) {
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
v = _mm_setzero_si128();
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], isARGB ? 2 : 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 1);
- v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 0);
- v = _mm_add_epi16(v, _mm_set1_epi16(0x80));
- v = _mm_srli_epi16(v, 8);
- v = _mm_insert_epi16(v, 255, 3);
- v = _mm_packus_epi16(v, v);
- dst[i] = _mm_cvtsi128_si32(v);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], isARGB ? 0 : 2);
+ storePU<T>(dst[i], v, isARGB ? 255 : 0xffff);
}
+}
+
+template<>
+void storeOpaque(QRgbaFloat32 *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ const __m128 vZero = _mm_set1_ps(0.0f);
+ const __m128 vOne = _mm_set1_ps(1.0f);
+ const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
+ for (qsizetype i = 0; i < len; ++i) {
+ __m128 vf = _mm_loadu_ps(&buffer[i].x);
+ const __m128 under = _mm_cmplt_ps(vf, vZero);
+ const __m128 over = _mm_cmpgt_ps(vf, vOne);
+ if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
+ // Within gamut
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
+ const int ridx = _mm_extract_epi16(v, 0);
+ const int gidx = _mm_extract_epi16(v, 2);
+ const int bidx = _mm_extract_epi16(v, 4);
+ v = _mm_setzero_si128();
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], 0);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 2);
+ v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], 4);
+ vf = _mm_mul_ps(_mm_cvtepi32_ps(v), viFF00);
+ _mm_store_ps(&dst[i].r, vf);
+ } else {
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
+ }
+ dst[i].a = 1.0f;
+ }
+}
+
+#elif defined(__ARM_NEON__)
+template<typename T>
+static inline void storeP(T &p, const uint16x4_t &v);
+template<>
+inline void storeP<QRgb>(QRgb &p, const uint16x4_t &v)
+{
+ p = vget_lane_u32(vreinterpret_u32_u8(vmovn_u16(vcombine_u16(v, v))), 0);
+}
+template<>
+inline void storeP<QRgba64>(QRgba64 &p, const uint16x4_t &v)
+{
+ vst1_u16((uint16_t *)&p, v);
+}
+
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ const float iFF00 = 1.0f / (255 * 256);
+ constexpr bool isARGB = isArgb<D>();
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = getAlpha<S>(src[i]);
+ float32x4_t vf = vld1q_f32(&buffer[i].x);
+ uint32x4_t v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f)));
+ const int ridx = vgetq_lane_u32(v, 0);
+ const int gidx = vgetq_lane_u32(v, 1);
+ const int bidx = vgetq_lane_u32(v, 2);
+ v = vsetq_lane_u32(d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], v, isARGB ? 2 : 0);
+ v = vsetq_lane_u32(d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], v, 1);
+ v = vsetq_lane_u32(d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], v, isARGB ? 0 : 2);
+ vf = vcvtq_f32_u32(v);
+ vf = vmulq_n_f32(vf, a * iFF00);
+ vf = vaddq_f32(vf, vdupq_n_f32(0.5f));
+ v = vcvtq_u32_f32(vf);
+ uint16x4_t v16 = vmovn_u32(v);
+ v16 = vset_lane_u16(a, v16, 3);
+ storeP<D>(dst[i], v16);
+ }
+}
+
+template<typename T>
+static inline void storePU(T &p, uint16x4_t &v, int a);
+template<>
+inline void storePU<QRgb>(QRgb &p, uint16x4_t &v, int a)
+{
+ v = vadd_u16(v, vdup_n_u16(0x80));
+ v = vshr_n_u16(v, 8);
+ v = vset_lane_u16(a, v, 3);
+ p = vget_lane_u32(vreinterpret_u32_u8(vmovn_u16(vcombine_u16(v, v))), 0);
+}
+template<>
+inline void storePU<QRgba64>(QRgba64 &p, uint16x4_t &v, int a)
+{
+ v = vadd_u16(v, vshr_n_u16(v, 8));
+ v = vset_lane_u16(a, v, 3);
+ vst1_u16((uint16_t *)&p, v);
+}
+
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ constexpr bool isARGB = isArgb<D>();
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = getAlpha<S>(src[i]);
+ float32x4_t vf = vld1q_f32(&buffer[i].x);
+ uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f))));
+ const int ridx = vget_lane_u16(v, 0);
+ const int gidx = vget_lane_u16(v, 1);
+ const int bidx = vget_lane_u16(v, 2);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], v, isARGB ? 2 : 0);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], v, 1);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], v, isARGB ? 0 : 2);
+ storePU<D>(dst[i], v, a);
+ }
+}
+
+template<typename T>
+static void storeOpaque(T *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ constexpr bool isARGB = isArgb<T>();
+ for (qsizetype i = 0; i < len; ++i) {
+ float32x4_t vf = vld1q_f32(&buffer[i].x);
+ uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f))));
+ const int ridx = vget_lane_u16(v, 0);
+ const int gidx = vget_lane_u16(v, 1);
+ const int bidx = vget_lane_u16(v, 2);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], v, isARGB ? 2 : 0);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], v, 1);
+ v = vset_lane_u16(d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], v, isARGB ? 0 : 2);
+ storePU<T>(dst[i], v, isARGB ? 255 : 0xffff);
+ }
+}
#else
+static void storePremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]);
+ const float fa = a / (255.0f * 256.0f);
+ const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * float(QColorTrcLut::Resolution) + 0.5f)];
+ dst[i] = qRgba(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a);
+ }
+}
+
+static void storeUnpremultiplied(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x);
+ const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y);
+ const int b = d_ptr->colorSpaceOut->lut[2]->u8FromLinearF32(buffer[i].z);
+ dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+static void storeOpaque(QRgb *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
for (qsizetype i = 0; i < len; ++i) {
const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y);
const int b = d_ptr->colorSpaceOut->lut[2]->u8FromLinearF32(buffer[i].z);
dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
}
-#endif
}
-static void storePremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+template<typename S>
+static void storePremultiplied(QRgba64 *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
- const int a = src[i].alpha();
+ const int a = getAlphaF(src[i]) * 65535.f;
const float fa = a / (255.0f * 256.0f);
- const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)];
- const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)];
- const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)];
+ const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * float(QColorTrcLut::Resolution) + 0.5f)];
dst[i] = qRgba64(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a);
}
}
-static void storeUnpremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+template<typename S>
+static void storeUnpremultiplied(QRgba64 *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
+ const int a = getAlphaF(src[i]) * 65535.f;
const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y);
const int b = d_ptr->colorSpaceOut->lut[2]->u16FromLinearF32(buffer[i].z);
- dst[i] = qRgba64(r, g, b, src[i].alpha());
+ dst[i] = qRgba64(r, g, b, a);
}
}
-static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(QRgba64 *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i) {
const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y);
@@ -609,6 +1177,75 @@ static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *bu
dst[i] = qRgba64(r, g, b, 0xFFFF);
}
}
+#endif
+#if !defined(__SSE2__)
+template<typename S>
+static void storePremultiplied(QRgbaFloat32 *dst, const S *src, const QColorVector *buffer,
+ const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float a = getAlphaF(src[i]);
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x) * a;
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y) * a;
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z) * a;
+ dst[i].a = a;
+ }
+}
+
+template<typename S>
+static void storeUnpremultiplied(QRgbaFloat32 *dst, const S *src, const QColorVector *buffer,
+ const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float a = getAlphaF(src[i]);
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
+ dst[i].a = a;
+ }
+}
+
+static void storeOpaque(QRgbaFloat32 *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
+ dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
+ dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
+ dst[i].a = 1.0f;
+ }
+}
+#endif
+
+static void loadGray(QColorVector *buffer, const quint8 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+}
+
+static void loadGray(QColorVector *buffer, const quint16 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+}
+
+static void storeOpaque(quint8 *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ dst[i] = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].y);
+}
+
+static void storeOpaque(quint16 *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ dst[i] = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].y);
+}
static constexpr qsizetype WorkBlockSize = 256;
@@ -621,19 +1258,493 @@ private:
alignas(T) char data[sizeof(T) * Count];
};
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
+{
+ const float f = 1.0f / 255.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const uint p = src[i];
+ buffer[i].x = qRed(p) * f;
+ buffer[i].y = qGreen(p) * f;
+ buffer[i].z = qBlue(p) * f;
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QCmyk32 *src, const qsizetype len)
+{
+ const float f = 1.0f / 255.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const QCmyk32 p = src[i];
+ buffer[i].x = (p.cyan() * f);
+ buffer[i].y = (p.magenta() * f);
+ buffer[i].z = (p.yellow() * f);
+ buffer[i].w = (p.black() * f);
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgba64 *src, const qsizetype len)
+{
+ const float f = 1.0f / 65535.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = src[i].red() * f;
+ buffer[i].y = src[i].green() * f;
+ buffer[i].z = src[i].blue() * f;
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = src[i].r;
+ buffer[i].y = src[i].g;
+ buffer[i].z = src[i].b;
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const uint p = src[i];
+ const float f = 1.0f / qAlpha(p);
+ buffer[i].x = (qRed(p) * f);
+ buffer[i].y = (qGreen(p) * f);
+ buffer[i].z = (qBlue(p) * f);
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *, const QCmyk32 *, const qsizetype)
+{
+ Q_UNREACHABLE();
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgba64 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float f = 1.0f / src[i].alpha();
+ buffer[i].x = (src[i].red() * f);
+ buffer[i].y = (src[i].green() * f);
+ buffer[i].z = (src[i].blue() * f);
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float f = 1.0f / src[i].a;
+ buffer[i].x = src[i].r * f;
+ buffer[i].y = src[i].g * f;
+ buffer[i].z = src[i].b * f;
+ }
+}
+template<typename T>
+static void storeUnpremultipliedLUT(QRgb *dst, const T *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+
+template<typename T>
+void storeUnpremultipliedLUT(QCmyk32 *dst, const T *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int c = buffer[i].x * 255.f;
+ const int m = buffer[i].y * 255.f;
+ const int y = buffer[i].z * 255.f;
+ const int k = buffer[i].w * 255.f;
+ dst[i] = QCmyk32(c, m, y, k);
+ }
+}
+
+template<typename T>
+static void storeUnpremultipliedLUT(QRgba64 *dst, const T *,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, 65535);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgba64 *dst, const QRgb *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]) * 257;
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgba64 *dst, const QRgba64 *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, src[i].alpha());
+ }
+}
+
+template<typename T>
+static void storeUnpremultipliedLUT(QRgbaFloat32 *dst, const T *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float r = buffer[i].x;
+ const float g = buffer[i].y;
+ const float b = buffer[i].z;
+ dst[i] = QRgbaFloat32{r, g, b, getAlphaF(src[i])};
+ }
+}
+
template<typename T>
-void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const
+static void storePremultipliedLUT(QRgb *, const T *, const QColorVector *, const qsizetype);
+
+template<>
+void storePremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]);
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgb *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+
+template<typename T>
+static void storePremultipliedLUT(QCmyk32 *dst, const T *src, const QColorVector *buffer, const qsizetype len)
+{
+ storeUnpremultipliedLUT(dst, src, buffer, len);
+}
+
+template<typename T>
+static void storePremultipliedLUT(QRgba64 *, const T *, const QColorVector *, const qsizetype);
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]) * 257;
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, 65535);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = src[i].alpha();
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<typename T>
+static void storePremultipliedLUT(QRgbaFloat32 *dst, const T *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float a = getAlphaF(src[i]);
+ const float r = buffer[i].x * a;
+ const float g = buffer[i].y * a;
+ const float b = buffer[i].z * a;
+ dst[i] = QRgbaFloat32{r, g, b, a};
+ }
+}
+
+static void visitElement(const QColorSpacePrivate::TransferElement &element, QColorVector *buffer, const qsizetype len)
+{
+ const bool doW = element.trc[3].isValid();
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = element.trc[0].apply(buffer[i].x);
+ buffer[i].y = element.trc[1].apply(buffer[i].y);
+ buffer[i].z = element.trc[2].apply(buffer[i].z);
+ if (doW)
+ buffer[i].w = element.trc[3].apply(buffer[i].w);
+ }
+}
+
+static void visitElement(const QColorMatrix &element, QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] = element.map(buffer[i]);
+}
+
+static void visitElement(const QColorVector &offset, QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] += offset;
+}
+
+static void visitElement(const QColorCLUT &element, QColorVector *buffer, const qsizetype len)
+{
+ if (element.isEmpty())
+ return;
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] = element.apply(buffer[i]);
+}
+
+/*!
+ \internal
+*/
+QColorVector QColorTransformPrivate::map(QColorVector c) const
+{
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ if (colorSpaceIn->lut.generated.loadAcquire()) {
+ c.x = colorSpaceIn->lut[0]->toLinear(c.x);
+ c.y = colorSpaceIn->lut[1]->toLinear(c.y);
+ c.z = colorSpaceIn->lut[2]->toLinear(c.z);
+ } else {
+ c.x = colorSpaceIn->trc[0].apply(c.x);
+ c.y = colorSpaceIn->trc[1].apply(c.y);
+ c.z = colorSpaceIn->trc[2].apply(c.z);
+ }
+ c = colorMatrix.map(c);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab)
+ c = c.xyzToLab();
+ else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab)
+ c = c.labToXyz();
+
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ if (!colorSpaceIn->isThreeComponentMatrix()) {
+ c = colorMatrix.map(c);
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+ }
+ if (colorSpaceOut->lut.generated.loadAcquire()) {
+ c.x = colorSpaceOut->lut[0]->fromLinear(c.x);
+ c.y = colorSpaceOut->lut[1]->fromLinear(c.y);
+ c.z = colorSpaceOut->lut[2]->fromLinear(c.z);
+ } else {
+ c.x = colorSpaceOut->trc[0].applyInverse(c.x);
+ c.y = colorSpaceOut->trc[1].applyInverse(c.y);
+ c.z = colorSpaceOut->trc[2].applyInverse(c.z);
+ }
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+ }
+ return c;
+}
+
+/*!
+ \internal
+*/
+QColorVector QColorTransformPrivate::mapExtended(QColorVector c) const
+{
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ c.x = colorSpaceIn->trc[0].applyExtended(c.x);
+ c.y = colorSpaceIn->trc[1].applyExtended(c.y);
+ c.z = colorSpaceIn->trc[2].applyExtended(c.z);
+ c = colorMatrix.map(c);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab)
+ c = c.xyzToLab();
+ else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab)
+ c = c.labToXyz();
+
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ if (!colorSpaceIn->isThreeComponentMatrix())
+ c = colorMatrix.map(c);
+ c.x = colorSpaceOut->trc[0].applyInverseExtended(c.x);
+ c.y = colorSpaceOut->trc[1].applyInverseExtended(c.y);
+ c.z = colorSpaceOut->trc[2].applyInverseExtended(c.z);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
+ return c;
+}
+
+template<typename S>
+void QColorTransformPrivate::applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
+{
+ // Avoid compiling this part for S=QCmyk32:
+ if constexpr (!std::is_same_v<S, QCmyk32>) {
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ if (flags & InputPremultiplied)
+ loadPremultiplied(buffer, src, len, this);
+ else
+ loadUnpremultiplied(buffer, src, len, this);
+
+ if (!colorSpaceOut->isThreeComponentMatrix())
+ applyMatrix<DoClamp>(buffer, len, colorMatrix); // colorMatrix should have the first half only.
+ return;
+ }
+ }
+ Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix());
+
+ if (flags & InputPremultiplied)
+ loadPremultipliedLUT(buffer, src, len);
+ else
+ loadUnpremultipliedLUT(buffer, src, len);
+
+ if constexpr (std::is_same_v<S, QRgbaFloat16> || std::is_same_v<S, QRgbaFloat32>)
+ clampIfNeeded<DoClamp>(buffer, len);
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+}
+
+template<typename D, typename S>
+void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
+{
+ constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
+ // Avoid compiling this part for D=QCmyk32:
+ if constexpr (!std::is_same_v<D, QCmyk32>) {
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ applyMatrix<doClamp>(buffer, len, colorMatrix); // colorMatrix should have the latter half only.
+
+ if constexpr (std::is_same_v<S, QCmyk32>) {
+ storeOpaque(dst, buffer, len, this);
+ } else {
+ if (flags & InputOpaque)
+ storeOpaque(dst, buffer, len, this);
+ else if (flags & OutputPremultiplied)
+ storePremultiplied(dst, src, buffer, len, this);
+ else
+ storeUnpremultiplied(dst, src, buffer, len, this);
+ }
+ return;
+ }
+ }
+ Q_ASSERT(!colorSpaceOut->isThreeComponentMatrix());
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+
+ clampIfNeeded<doClamp>(buffer, len);
+
+ if (flags & OutputPremultiplied)
+ storePremultipliedLUT(dst, src, buffer, len);
+ else
+ storeUnpremultipliedLUT(dst, src, buffer, len);
+}
+
+template<typename D, typename S>
+void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix());
+
+ if (!colorMatrix.isValid())
+ return;
+
+ if (colorSpaceIn->isThreeComponentMatrix())
+ updateLutsIn();
+ if (colorSpaceOut->isThreeComponentMatrix())
+ updateLutsOut();
+
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+
+ applyConvertIn(src + i, buffer, len, flags);
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+
+ applyConvertOut(dst + i, src + i, buffer, len, flags);
+
+ i += len;
+ }
+}
+
+template<typename D, typename S>
+void QColorTransformPrivate::applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ Q_ASSERT(colorSpaceIn->isThreeComponentMatrix() && colorSpaceOut->isThreeComponentMatrix());
+
if (!colorMatrix.isValid())
return;
updateLutsIn();
updateLutsOut();
- bool doApplyMatrix = (colorMatrix != QColorMatrix::identity());
+ bool doApplyMatrix = !colorMatrix.isIdentity();
+ constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
QUninitialized<QColorVector, WorkBlockSize> buffer;
-
qsizetype i = 0;
while (i < count) {
const qsizetype len = qMin(count - i, WorkBlockSize);
@@ -643,10 +1754,12 @@ void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, Transf
loadUnpremultiplied(buffer, src + i, len, this);
if (doApplyMatrix)
- applyMatrix(buffer, len, colorMatrix);
+ applyMatrix<doClamp>(buffer, len, colorMatrix);
+ else
+ clampIfNeeded<doClamp>(buffer, len);
if (flags & InputOpaque)
- storeOpaque(dst + i, src + i, buffer, len, this);
+ storeOpaque(dst + i, buffer, len, this);
else if (flags & OutputPremultiplied)
storePremultiplied(dst + i, src + i, buffer, len, this);
else
@@ -658,9 +1771,155 @@ void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, Transf
/*!
\internal
+ Applies the color transformation on \a count S pixels starting from
+ \a src and stores the result in \a dst as D pixels .
+
+ Assumes unpremultiplied data by default. Set \a flags to change defaults.
+
+ \sa prepare()
+*/
+template<typename D, typename S>
+void QColorTransformPrivate::apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ if constexpr (!std::is_same_v<D, QCmyk32> && !std::is_same_v<S, QCmyk32>) {
+ if (isThreeComponentMatrix())
+ return applyThreeComponentMatrix<D, S>(dst, src, count, flags);
+ }
+ applyElementListTransform<D, S>(dst, src, count, flags);
+}
+
+/*!
+ \internal
+ Is to be called on a color-transform to XYZ, returns only luminance values.
+
+ */
+template<typename D, typename S>
+void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
+ updateLutsOut();
+ if (!colorSpaceIn->isThreeComponentMatrix()) {
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+
+ applyConvertIn(src, buffer, len, flags);
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+ storeOpaque(dst + i, buffer, len, this);
+
+ i += len;
+ }
+ return;
+ }
+ if constexpr (!std::is_same_v<S, QCmyk32>) {
+ if (!colorMatrix.isValid())
+ return;
+
+ updateLutsIn();
+
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ if (flags & InputPremultiplied)
+ loadPremultiplied(buffer, src + i, len, this);
+ else
+ loadUnpremultiplied(buffer, src + i, len, this);
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+
+ storeOpaque(dst + i, buffer, len, this);
+
+ i += len;
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
+/*!
+ \internal
+*/
+template<typename D, typename S>
+void QColorTransformPrivate::applyGray(D *dst, const S *src, qsizetype count, TransformFlags) const
+{
+ Q_ASSERT(colorSpaceIn->isThreeComponentMatrix());
+ updateLutsIn();
+ if constexpr (std::is_same_v<D, QRgb> || std::is_same_v<D, QRgba64> || std::is_same_v<D, QRgbaFloat32> || std::is_same_v<D, QCmyk32>) {
+ if (!colorSpaceOut->isThreeComponentMatrix()) {
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ loadGray(buffer, src + i, len, this);
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+
+ clampIfNeeded<DoClamp>(buffer, len);
+
+ storeUnpremultipliedLUT(dst, src, buffer, len); // input is always opaque
+
+ i += len;
+ }
+ return;
+ }
+ }
+ Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
+ if constexpr (!std::is_same_v<D, QCmyk32>) {
+ if (!colorMatrix.isValid())
+ return;
+
+ updateLutsOut();
+
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ loadGray(buffer, src + i, len, this);
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+
+ storeOpaque(dst + i, buffer, len, this);
+ i += len;
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
+/*!
+ \internal
\enum QColorTransformPrivate::TransformFlag
- Defines how the transform is to be applied.
+ Defines how the transform should handle alpha values.
\value Unpremultiplied The input and output should both be unpremultiplied.
\value InputOpaque The input is guaranteed to be opaque.
@@ -684,37 +1943,72 @@ void QColorTransformPrivate::prepare()
updateLutsOut();
}
-/*!
- \internal
- Applies the color transformation on \a count QRgb pixels starting from
- \a src and stores the result in \a dst.
-
- Thread-safe if prepare() has been called first.
-
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
-
- \sa prepare()
-*/
-void QColorTransformPrivate::apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const
+// Only allow versions increasing precision
+template void QColorTransformPrivate::applyReturnGray<quint8, QRgb>(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint8, QCmyk32>(quint8 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint16, QCmyk32>(quint16 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint16, QRgba64>(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint8, quint8>(quint8 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint16, quint8>(quint16 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint16, quint16>(quint16 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QRgb, quint8>(QRgb *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QCmyk32, quint8>(QCmyk32 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QCmyk32, quint16>(QCmyk32 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QRgba64, quint16>(QRgba64 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+
+template void QColorTransformPrivate::apply<QRgb, QRgb>(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgb, QCmyk32>(QRgb *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgb>(QCmyk32 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QCmyk32>(QCmyk32 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgba64>(QCmyk32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgbaFloat32>(QCmyk32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QRgb>(QRgba64 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QCmyk32>(QRgba64 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QRgba64>(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgb>(QRgbaFloat32 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QCmyk32>(QRgbaFloat32 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgba64>(QRgbaFloat32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
+
+bool QColorTransformPrivate::isThreeComponentMatrix() const
{
- apply<QRgb>(dst, src, count, flags);
+ if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
+ return false;
+ if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
+ return false;
+ return true;
}
/*!
\internal
- Applies the color transformation on \a count QRgba64 pixels starting from
- \a src and stores the result in \a dst.
-
- Thread-safe if prepare() has been called first.
-
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
-
- \sa prepare()
*/
-void QColorTransformPrivate::apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const
+bool QColorTransformPrivate::isIdentity() const
{
- apply<QRgba64>(dst, src, count, flags);
+ if (colorSpaceIn == colorSpaceOut)
+ return true;
+ if (!colorMatrix.isIdentity())
+ return false;
+ if (colorSpaceIn && colorSpaceOut) {
+ if (colorSpaceIn->equals(colorSpaceOut.constData()))
+ return true;
+ if (!isThreeComponentMatrix())
+ return false;
+ if (colorSpaceIn->transferFunction != colorSpaceOut->transferFunction)
+ return false;
+ if (colorSpaceIn->transferFunction == QColorSpace::TransferFunction::Custom) {
+ return colorSpaceIn->trc[0] == colorSpaceOut->trc[0]
+ && colorSpaceIn->trc[1] == colorSpaceOut->trc[1]
+ && colorSpaceIn->trc[2] == colorSpaceOut->trc[2];
+ }
+ } else {
+ if (!isThreeComponentMatrix())
+ return false;
+ if (colorSpaceIn && colorSpaceIn->transferFunction != QColorSpace::TransferFunction::Linear)
+ return false;
+ if (colorSpaceOut && colorSpaceOut->transferFunction != QColorSpace::TransferFunction::Linear)
+ return false;
+ }
+ return true;
}
-
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolortransform.h b/src/gui/painting/qcolortransform.h
index 94b6b3a385..02f15ee89f 100644
--- a/src/gui/painting/qcolortransform.h
+++ b/src/gui/painting/qcolortransform.h
@@ -1,47 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRANSFORM_H
#define QCOLORTRANSFORM_H
#include <QtGui/qtguiglobal.h>
#include <QtGui/qrgb.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@@ -49,39 +14,48 @@ class QColor;
class QRgba64;
class QColorSpacePrivate;
class QColorTransformPrivate;
+class qfloat16;
+template<typename T>
+class QRgbaFloat;
+typedef QRgbaFloat<qfloat16> QRgbaFloat16;
+typedef QRgbaFloat<float> QRgbaFloat32;
+
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QColorTransformPrivate, Q_GUI_EXPORT)
class QColorTransform
{
public:
- QColorTransform() noexcept : d(nullptr) { }
+ QColorTransform() noexcept = default;
Q_GUI_EXPORT ~QColorTransform();
Q_GUI_EXPORT QColorTransform(const QColorTransform &colorTransform) noexcept;
- QColorTransform(QColorTransform &&colorTransform) noexcept
- : d{qExchange(colorTransform.d, nullptr)}
- { }
+ QColorTransform(QColorTransform &&colorTransform) = default;
QColorTransform &operator=(const QColorTransform &other) noexcept
{
QColorTransform{other}.swap(*this);
return *this;
}
- QColorTransform &operator=(QColorTransform &&other) noexcept
- {
- QColorTransform{std::move(other)}.swap(*this);
- return *this;
- }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QColorTransform)
- void swap(QColorTransform &other) noexcept { qSwap(d, other.d); }
+ void swap(QColorTransform &other) noexcept { d.swap(other.d); }
+ Q_GUI_EXPORT bool isIdentity() const noexcept;
Q_GUI_EXPORT QRgb map(QRgb argb) const;
Q_GUI_EXPORT QRgba64 map(QRgba64 rgba64) const;
+ Q_GUI_EXPORT QRgbaFloat16 map(QRgbaFloat16 rgbafp16) const;
+ Q_GUI_EXPORT QRgbaFloat32 map(QRgbaFloat32 rgbafp32) const;
Q_GUI_EXPORT QColor map(const QColor &color) const;
+ friend bool operator==(const QColorTransform &ct1, const QColorTransform &ct2)
+ { return ct1.compare(ct2); }
+ friend bool operator!=(const QColorTransform &ct1, const QColorTransform &ct2)
+ { return !ct1.compare(ct2); }
+
private:
- friend class QColorSpace;
friend class QColorSpacePrivate;
- friend class QImage;
+ friend class QColorTransformPrivate;
+ Q_GUI_EXPORT bool compare(const QColorTransform &other) const;
- const QColorTransformPrivate *d;
+ QExplicitlySharedDataPointer<QColorTransformPrivate> d;
};
Q_DECLARE_SHARED(QColorTransform)
diff --git a/src/gui/painting/qcolortransform_p.h b/src/gui/painting/qcolortransform_p.h
index 5d7116248d..59ea6a2405 100644
--- a/src/gui/painting/qcolortransform_p.h
+++ b/src/gui/painting/qcolortransform_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRANSFORM_P_H
#define QCOLORTRANSFORM_P_H
@@ -55,8 +19,10 @@
#include "qcolorspace_p.h"
#include <QtCore/qshareddata.h>
+#include <QtGui/qrgbafloat.h>
QT_BEGIN_NAMESPACE
+class QCmyk32;
class QColorTransformPrivate : public QSharedData
{
@@ -65,11 +31,15 @@ public:
QExplicitlySharedDataPointer<const QColorSpacePrivate> colorSpaceIn;
QExplicitlySharedDataPointer<const QColorSpacePrivate> colorSpaceOut;
+ static QColorTransformPrivate *get(const QColorTransform &q)
+ { return q.d.data(); }
+
void updateLutsIn() const;
void updateLutsOut() const;
- bool simpleGammaCorrection() const;
+ bool isIdentity() const;
+ bool isThreeComponentMatrix() const;
- void prepare();
+ Q_GUI_EXPORT void prepare();
enum TransformFlag {
Unpremultiplied = 0,
InputOpaque = 1,
@@ -79,11 +49,25 @@ public:
};
Q_DECLARE_FLAGS(TransformFlags, TransformFlag)
- void apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
- void apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
+ QColorVector map(QColorVector color) const;
+ QColorVector mapExtended(QColorVector color) const;
+
+ template<typename D, typename S>
+ void apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
- template<typename T>
- void apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const;
+private:
+ template<typename S>
+ void applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h
index 3ef9d442fc..d1ad1987df 100644
--- a/src/gui/painting/qcolortrc_p.h
+++ b/src/gui/painting/qcolortrc_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRC_P_H
#define QCOLORTRC_P_H
@@ -57,17 +21,15 @@
QT_BEGIN_NAMESPACE
-
-// Defines an ICC TRC (Tone Reproduction Curve)
+// Defines a TRC (Tone Reproduction Curve)
class Q_GUI_EXPORT QColorTrc
{
public:
- QColorTrc() noexcept : m_type(Type::Uninitialized)
- { }
- QColorTrc(const QColorTransferFunction &fun) : m_type(Type::Function), m_fun(fun)
- { }
- QColorTrc(const QColorTransferTable &table) : m_type(Type::Table), m_table(table)
- { }
+ QColorTrc() noexcept : m_type(Type::Uninitialized) { }
+ QColorTrc(const QColorTransferFunction &fun) : m_type(Type::Function), m_fun(fun) { }
+ QColorTrc(const QColorTransferTable &table) : m_type(Type::Table), m_table(table) { }
+ QColorTrc(QColorTransferFunction &&fun) noexcept : m_type(Type::Function), m_fun(std::move(fun)) { }
+ QColorTrc(QColorTransferTable &&table) noexcept : m_type(Type::Table), m_table(std::move(table)) { }
enum class Type {
Uninitialized,
@@ -75,9 +37,10 @@ public:
Table
};
- bool isLinear() const
+ bool isIdentity() const
{
- return m_type == Type::Uninitialized || (m_type == Type::Function && m_fun.isLinear());
+ return (m_type == Type::Function && m_fun.isIdentity())
+ || (m_type == Type::Table && m_table.isIdentity());
}
bool isValid() const
{
@@ -114,7 +77,7 @@ public:
if (x >= 0.0f && x <= 1.0f)
return applyInverse(x);
if (m_type == Type::Function)
- return std::copysign(applyInverse(x), x);
+ return std::copysign(applyInverse(std::abs(x)), x);
if (m_type == Type::Table)
return x < 0.0f ? 0.0f : 1.0f;
return x;
diff --git a/src/gui/painting/qcolortrclut.cpp b/src/gui/painting/qcolortrclut.cpp
index 268d7252b4..8a7673bc00 100644
--- a/src/gui/painting/qcolortrclut.cpp
+++ b/src/gui/painting/qcolortrclut.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcolortrclut_p.h"
#include "qcolortransferfunction_p.h"
@@ -43,44 +7,86 @@
#include <qmath.h>
QT_BEGIN_NAMESPACE
-
-QColorTrcLut *QColorTrcLut::fromGamma(qreal gamma)
+std::shared_ptr<QColorTrcLut> QColorTrcLut::create()
{
- QColorTrcLut *cp = new QColorTrcLut;
+ struct Access : QColorTrcLut {};
+ return std::make_shared<Access>();
+}
- for (int i = 0; i <= (255 * 16); ++i) {
- cp->m_toLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), gamma) * (255 * 256)));
- cp->m_fromLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), qreal(1) / gamma) * (255 * 256)));
- }
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromGamma(qreal gamma, Direction dir)
+{
+ auto cp = create();
+ cp->setFromGamma(gamma, dir);
+ return cp;
+}
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferFunction(const QColorTransferFunction &fun, Direction dir)
+{
+ auto cp = create();
+ cp->setFromTransferFunction(fun, dir);
return cp;
}
-QColorTrcLut *QColorTrcLut::fromTransferFunction(const QColorTransferFunction &fun)
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferTable(const QColorTransferTable &table, Direction dir)
{
- QColorTrcLut *cp = new QColorTrcLut;
- QColorTransferFunction inv = fun.inverted();
+ auto cp = create();
+ cp->setFromTransferTable(table, dir);
+ return cp;
+}
- for (int i = 0; i <= (255 * 16); ++i) {
- cp->m_toLinear[i] = ushort(qRound(fun.apply(i / qreal(255 * 16)) * (255 * 256)));
- cp->m_fromLinear[i] = ushort(qRound(inv.apply(i / qreal(255 * 16)) * (255 * 256)));
+void QColorTrcLut::setFromGamma(qreal gamma, Direction dir)
+{
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qRound(qPow(i / qreal(Resolution), gamma) * (255 * 256)));
}
- return cp;
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_fromLinear[i] = ushort(qRound(qPow(i / qreal(Resolution), qreal(1) / gamma) * (255 * 256)));
+ }
}
-QColorTrcLut *QColorTrcLut::fromTransferTable(const QColorTransferTable &table)
+void QColorTrcLut::setFromTransferFunction(const QColorTransferFunction &fun, Direction dir)
{
- QColorTrcLut *cp = new QColorTrcLut;
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qRound(fun.apply(i / qreal(Resolution)) * (255 * 256)));
+ }
- float minInverse = 0.0f;
- for (int i = 0; i <= (255 * 16); ++i) {
- cp->m_toLinear[i] = ushort(qBound(0, qRound(table.apply(i / qreal(255 * 16)) * (255 * 256)), 65280));
- minInverse = table.applyInverse(i / qreal(255 * 16), minInverse);
- cp->m_fromLinear[i] = ushort(qBound(0, qRound(minInverse * (255 * 256)), 65280));
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ QColorTransferFunction inv = fun.inverted();
+ for (int i = 0; i <= Resolution; ++i)
+ m_fromLinear[i] = ushort(qRound(inv.apply(i / qreal(Resolution)) * (255 * 256)));
}
+}
- return cp;
+void QColorTrcLut::setFromTransferTable(const QColorTransferTable &table, Direction dir)
+{
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qBound(0, qRound(table.apply(i / qreal(Resolution)) * (255 * 256)), 65280));
+ }
+
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ float minInverse = 0.0f;
+ for (int i = 0; i <= Resolution; ++i) {
+ minInverse = table.applyInverse(i / qreal(Resolution), minInverse);
+ m_fromLinear[i] = ushort(qBound(0, qRound(minInverse * (255 * 256)), 65280));
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolortrclut_p.h b/src/gui/painting/qcolortrclut_p.h
index 76a6a60803..3ebab42809 100644
--- a/src/gui/painting/qcolortrclut_p.h
+++ b/src/gui/painting/qcolortrclut_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORTRCLUT_P_H
#define QCOLORTRCLUT_P_H
@@ -52,11 +16,11 @@
//
#include <QtGui/private/qtguiglobal_p.h>
-#include <QtCore/qsharedpointer.h>
#include <QtGui/qrgb.h>
#include <QtGui/qrgba64.h>
#include <cmath>
+#include <memory>
#if defined(__SSE2__)
#include <emmintrin.h>
@@ -69,12 +33,25 @@ QT_BEGIN_NAMESPACE
class QColorTransferFunction;
class QColorTransferTable;
-class Q_GUI_EXPORT QColorTrcLut : public QEnableSharedFromThis<QColorTrcLut>
+class Q_GUI_EXPORT QColorTrcLut
{
public:
- static QColorTrcLut *fromGamma(qreal gamma);
- static QColorTrcLut *fromTransferFunction(const QColorTransferFunction &transfn);
- static QColorTrcLut *fromTransferTable(const QColorTransferTable &transTable);
+ static constexpr uint32_t ShiftUp = 4; // Amount to shift up from 1->255
+ static constexpr uint32_t ShiftDown = (8 - ShiftUp); // Amount to shift down from 1->65280
+ static constexpr qsizetype Resolution = (1 << ShiftUp) * 255; // Number of entries in table
+
+ enum Direction {
+ ToLinear = 1,
+ FromLinear = 2,
+ BiLinear = ToLinear | FromLinear
+ };
+
+ static std::shared_ptr<QColorTrcLut> fromGamma(qreal gamma, Direction dir = BiLinear);
+ static std::shared_ptr<QColorTrcLut> fromTransferFunction(const QColorTransferFunction &transFn, Direction dir = BiLinear);
+ static std::shared_ptr<QColorTrcLut> fromTransferTable(const QColorTransferTable &transTable, Direction dir = BiLinear);
+ void setFromGamma(qreal gamma, Direction dir = BiLinear);
+ void setFromTransferFunction(const QColorTransferFunction &transFn, Direction dir = BiLinear);
+ void setFromTransferTable(const QColorTransferTable &transTable, Direction dir = BiLinear);
// The following methods all convert opaque or unpremultiplied colors:
@@ -83,7 +60,7 @@ public:
#if defined(__SSE2__)
__m128i v = _mm_cvtsi32_si128(rgb32);
v = _mm_unpacklo_epi8(v, _mm_setzero_si128());
- const __m128i vidx = _mm_slli_epi16(v, 4);
+ const __m128i vidx = _mm_slli_epi16(v, ShiftUp);
const int ridx = _mm_extract_epi16(vidx, 2);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 0);
@@ -98,7 +75,7 @@ public:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint8x8_t v8 = vreinterpret_u8_u32(vmov_n_u32(rgb32));
uint16x4_t v16 = vget_low_u16(vmovl_u8(v8));
- const uint16x4_t vidx = vshl_n_u16(v16, 4);
+ const uint16x4_t vidx = vshl_n_u16(v16, ShiftUp);
const int ridx = vget_lane_u16(vidx, 2);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 0);
@@ -109,42 +86,43 @@ public:
v16 = vadd_u16(v16, vshr_n_u16(v16, 8));
return QRgba64::fromRgba64(vget_lane_u64(vreinterpret_u64_u16(v16), 0));
#else
- uint r = m_toLinear[qRed(rgb32) << 4];
- uint g = m_toLinear[qGreen(rgb32) << 4];
- uint b = m_toLinear[qBlue(rgb32) << 4];
+ uint r = m_toLinear[qRed(rgb32) << ShiftUp];
+ uint g = m_toLinear[qGreen(rgb32) << ShiftUp];
+ uint b = m_toLinear[qBlue(rgb32) << ShiftUp];
r = r + (r >> 8);
g = g + (g >> 8);
b = b + (b >> 8);
return QRgba64::fromRgba64(r, g, b, qAlpha(rgb32) * 257);
#endif
}
+ QRgba64 toLinear64(QRgba64) const = delete;
QRgb toLinear(QRgb rgb32) const
{
- return convertWithTable(rgb32, m_toLinear);
+ return convertWithTable(rgb32, m_toLinear.get());
}
QRgba64 toLinear(QRgba64 rgb64) const
{
- return convertWithTable(rgb64, m_toLinear);
+ return convertWithTable(rgb64, m_toLinear.get());
}
float u8ToLinearF32(int c) const
{
- ushort v = m_toLinear[c << 4];
+ ushort v = m_toLinear[c << ShiftUp];
return v * (1.0f / (255*256));
}
float u16ToLinearF32(int c) const
{
c -= (c >> 8);
- ushort v = m_toLinear[c >> 4];
+ ushort v = m_toLinear[c >> ShiftDown];
return v * (1.0f / (255*256));
}
float toLinear(float f) const
{
- ushort v = m_toLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_toLinear[(int)(f * Resolution + 0.5f)];
return v * (1.0f / (255*256));
}
@@ -153,7 +131,7 @@ public:
#if defined(__SSE2__)
__m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgb64));
v = _mm_sub_epi16(v, _mm_srli_epi16(v, 8));
- const __m128i vidx = _mm_srli_epi16(v, 4);
+ const __m128i vidx = _mm_srli_epi16(v, ShiftDown);
const int ridx = _mm_extract_epi16(vidx, 0);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 2);
@@ -167,7 +145,7 @@ public:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint16x4_t v = vreinterpret_u16_u64(vmov_n_u64(rgb64));
v = vsub_u16(v, vshr_n_u16(v, 8));
- const uint16x4_t vidx = vshr_n_u16(v, 4);
+ const uint16x4_t vidx = vshr_n_u16(v, ShiftDown);
const int ridx = vget_lane_u16(vidx, 0);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 2);
@@ -186,54 +164,56 @@ public:
g = g - (g >> 8);
b = b - (b >> 8);
a = (a + 0x80) >> 8;
- r = (m_fromLinear[r >> 4] + 0x80) >> 8;
- g = (m_fromLinear[g >> 4] + 0x80) >> 8;
- b = (m_fromLinear[b >> 4] + 0x80) >> 8;
+ r = (m_fromLinear[r >> ShiftDown] + 0x80) >> 8;
+ g = (m_fromLinear[g >> ShiftDown] + 0x80) >> 8;
+ b = (m_fromLinear[b >> ShiftDown] + 0x80) >> 8;
return (a << 24) | (r << 16) | (g << 8) | b;
#endif
}
QRgb fromLinear(QRgb rgb32) const
{
- return convertWithTable(rgb32, m_fromLinear);
+ return convertWithTable(rgb32, m_fromLinear.get());
}
QRgba64 fromLinear(QRgba64 rgb64) const
{
- return convertWithTable(rgb64, m_fromLinear);
+ return convertWithTable(rgb64, m_fromLinear.get());
}
int u8FromLinearF32(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return (v + 0x80) >> 8;
}
int u16FromLinearF32(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return v + (v >> 8);
}
float fromLinear(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return v * (1.0f / (255*256));
}
// We translate to 0-65280 (255*256) instead to 0-65535 to make simple
// shifting an accurate conversion.
- // We translate from 0-4080 (255*16) for the same speed up, and to keep
- // the tables small enough to fit in most inner caches.
- ushort m_toLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280]
- ushort m_fromLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280]
+ // We translate from 0->Resolution (4080 = 255*16) for the same speed up,
+ // and to keep the tables small enough to fit in most inner caches.
+ std::unique_ptr<ushort[]> m_toLinear; // [0->Resolution] -> [0-65280]
+ std::unique_ptr<ushort[]> m_fromLinear; // [0->Resolution] -> [0-65280]
private:
- QColorTrcLut() { }
+ QColorTrcLut() = default;
+
+ static std::shared_ptr<QColorTrcLut> create();
Q_ALWAYS_INLINE static QRgb convertWithTable(QRgb rgb32, const ushort *table)
{
- const int r = (table[qRed(rgb32) << 4] + 0x80) >> 8;
- const int g = (table[qGreen(rgb32) << 4] + 0x80) >> 8;
- const int b = (table[qBlue(rgb32) << 4] + 0x80) >> 8;
+ const int r = (table[qRed(rgb32) << ShiftUp] + 0x80) >> 8;
+ const int g = (table[qGreen(rgb32) << ShiftUp] + 0x80) >> 8;
+ const int b = (table[qBlue(rgb32) << ShiftUp] + 0x80) >> 8;
return (rgb32 & 0xff000000) | (r << 16) | (g << 8) | b;
}
Q_ALWAYS_INLINE static QRgba64 convertWithTable(QRgba64 rgb64, const ushort *table)
@@ -241,7 +221,7 @@ private:
#if defined(__SSE2__)
__m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgb64));
v = _mm_sub_epi16(v, _mm_srli_epi16(v, 8));
- const __m128i vidx = _mm_srli_epi16(v, 4);
+ const __m128i vidx = _mm_srli_epi16(v, ShiftDown);
const int ridx = _mm_extract_epi16(vidx, 2);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 0);
@@ -255,7 +235,7 @@ private:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint16x4_t v = vreinterpret_u16_u64(vmov_n_u64(rgb64));
v = vsub_u16(v, vshr_n_u16(v, 8));
- const uint16x4_t vidx = vshr_n_u16(v, 4);
+ const uint16x4_t vidx = vshr_n_u16(v, ShiftDown);
const int ridx = vget_lane_u16(vidx, 2);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 0);
@@ -271,9 +251,9 @@ private:
r = r - (r >> 8);
g = g - (g >> 8);
b = b - (b >> 8);
- r = table[r >> 4];
- g = table[g >> 4];
- b = table[b >> 4];
+ r = table[r >> ShiftDown];
+ g = table[g >> ShiftDown];
+ b = table[b >> ShiftDown];
r = r + (r >> 8);
g = g + (g >> 8);
b = b + (b >> 8);
diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp
index ced213e36d..00fd749fe6 100644
--- a/src/gui/painting/qcompositionfunctions.cpp
+++ b/src/gui/painting/qcompositionfunctions.cpp
@@ -1,45 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qglobal.h>
+
#include "qdrawhelper_p.h"
#include "qrgba64_p.h"
+#include "qrgbafloat.h"
QT_BEGIN_NAMESPACE
@@ -117,6 +83,8 @@ struct Argb32OperationsC
const Argb32OperationsC::Type Argb32OperationsC::clear = 0;
+typedef Argb32OperationsC Argb32Operations;
+
struct Rgba64OperationsBase
{
typedef QRgba64 Type;
@@ -319,9 +287,188 @@ typedef Rgba64OperationsNEON Rgba64Operations;
#else
typedef Rgba64OperationsC Rgba64Operations;
#endif
+
#endif // QT_CONFIG(raster_64bit)
-typedef Argb32OperationsC Argb32Operations;
+#if QT_CONFIG(raster_fp)
+
+static inline QRgbaFloat32 qRgbaFloat32(float r, float g, float b, float a)
+{
+ return QRgbaFloat32{r, g, b, a};
+}
+
+struct RgbaFPOperationsBase
+{
+ typedef QRgbaFloat32 Type;
+ typedef float Scalar;
+
+ static inline constexpr Type clear = { 0, 0, 0, 0 };
+
+ static bool isOpaque(Type val)
+ { return val.a >= 1.0f; }
+ static bool isTransparent(Type val)
+ { return val.a <= 0.0f; }
+ static Scalar scalarFrom8bit(uint8_t a)
+ { return a * (1.0f / 255.0f); }
+
+ static void memfill(Type *ptr, Type value, qsizetype len)
+ {
+ for (qsizetype i = 0; i < len; ++i)
+ ptr[i] = value;
+ }
+ static void memcpy(Type *Q_DECL_RESTRICT dest, const Type *Q_DECL_RESTRICT src, qsizetype len)
+ { ::memcpy(dest, src, len * sizeof(Type)); }
+};
+
+struct RgbaFPOperationsC : RgbaFPOperationsBase
+{
+ typedef QRgbaFloat32 OptimalType;
+ typedef float OptimalScalar;
+
+ static OptimalType load(const Type *ptr)
+ {
+ return QRgbaFloat32 { ptr->r, ptr->g, ptr->b, ptr->a };
+ }
+ static OptimalType convert(const Type &val)
+ {
+ return QRgbaFloat32 { val.r, val.g, val.b, val.a };
+ }
+ static void store(Type *ptr, OptimalType value)
+ {
+ ptr->r = value.r;
+ ptr->g = value.g;
+ ptr->b = value.b;
+ ptr->a = value.a;
+ }
+ static OptimalType add(OptimalType a, OptimalType b)
+ {
+ a.r += b.r;
+ a.g += b.g;
+ a.b += b.b;
+ a.a += b.a;
+ return a;
+ }
+ static OptimalScalar add(OptimalScalar a, OptimalScalar b)
+ { return a + b; }
+ static OptimalType plus(OptimalType a, OptimalType b)
+ {
+ a = add(a, b); // no saturation on color values
+ if (a.a < 0.0f) a.a = 0.0f;
+ else if (a.a > 1.0f) a.a = 1.0f;
+ return a;
+ }
+ static OptimalScalar alpha(OptimalType val)
+ { return val.a; }
+ static OptimalScalar invAlpha(OptimalScalar c)
+ { return 1.0f - c; }
+ static OptimalScalar invAlpha(OptimalType val)
+ { return 1.0f - val.a; }
+ static OptimalScalar scalar(Scalar v)
+ { return v; }
+ static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
+ {
+ val.r *= a;
+ val.g *= a;
+ val.b *= a;
+ val.a *= a;
+ return val;
+ }
+ static OptimalScalar multiplyAlpha8bit(OptimalScalar val, uint8_t a)
+ {
+ return val * a * (1.0f / 255.0f);
+ }
+ static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
+ {
+ return add(multiplyAlpha(x, a1), multiplyAlpha(y, a2));
+ }
+ static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
+ {
+ return multiplyAlpha(val, a * (1.0f / 255.0f));
+ }
+ static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
+ {
+ return add(multiplyAlpha8bit(x, a1), multiplyAlpha8bit(y, a2));
+ }
+};
+
+#if defined(__SSE2__)
+struct RgbaFPOperationsSSE2 : public RgbaFPOperationsBase
+{
+ typedef __m128 OptimalType;
+ typedef __m128 OptimalScalar;
+
+ static OptimalType Q_DECL_VECTORCALL load(const Type *ptr)
+ {
+ return _mm_loadu_ps(reinterpret_cast<const float *>(ptr));
+ }
+ static OptimalType Q_DECL_VECTORCALL convert(const Type &value)
+ {
+ return load(&value);
+ }
+ static void Q_DECL_VECTORCALL store(Type *ptr, OptimalType value)
+ {
+ _mm_storeu_ps(reinterpret_cast<float *>(ptr), value);
+ }
+ static OptimalType Q_DECL_VECTORCALL add(OptimalType a, OptimalType b)
+ {
+ return _mm_add_ps(a, b);
+ }
+// same as above:
+// static OptimalScalar add(OptimalScalar a, OptimalScalar b)
+ static OptimalType Q_DECL_VECTORCALL plus(OptimalType a, OptimalType b)
+ {
+ a = _mm_add_ps(a, b);
+ __m128 aa = _mm_min_ps(a, _mm_set1_ps(1.0f));
+ aa = _mm_max_ps(aa, _mm_set1_ps(0.0f));
+ // An indirect insert using only SSE2:
+ aa = _mm_shuffle_ps(aa, a, _MM_SHUFFLE(2, 2, 3, 3));
+ a = _mm_shuffle_ps(a, aa, _MM_SHUFFLE(0, 2, 1, 0));
+ return a;
+ }
+ static OptimalScalar Q_DECL_VECTORCALL alpha(OptimalType c)
+ {
+ return _mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3));
+ }
+ static OptimalScalar Q_DECL_VECTORCALL invAlpha(Scalar c)
+ {
+ return _mm_set1_ps(1.0f - float(c));
+ }
+ static OptimalScalar Q_DECL_VECTORCALL invAlpha(OptimalType c)
+ {
+ return _mm_sub_ps(_mm_set1_ps(1.0f), alpha(c));
+ }
+ static OptimalScalar Q_DECL_VECTORCALL scalar(Scalar n)
+ {
+ return _mm_set1_ps(float(n));
+ }
+ static OptimalType Q_DECL_VECTORCALL multiplyAlpha(OptimalType val, OptimalScalar a)
+ {
+ return _mm_mul_ps(val, a);
+ }
+ static OptimalType Q_DECL_VECTORCALL interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
+ {
+ return add(multiplyAlpha(x, a1), multiplyAlpha(y, a2));
+ }
+ static OptimalType Q_DECL_VECTORCALL multiplyAlpha8bit(OptimalType val, uint8_t a)
+ {
+ return multiplyAlpha(val, _mm_set1_ps(a * (1.0f / 255.0f)));
+ }
+// same as above:
+// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a)
+ static OptimalType Q_DECL_VECTORCALL interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
+ {
+ return add(multiplyAlpha8bit(x, a1), multiplyAlpha8bit(y, a2));
+ }
+};
+#endif
+
+#if defined(__SSE2__)
+typedef RgbaFPOperationsSSE2 RgbaFPOperations;
+#else
+typedef RgbaFPOperationsC RgbaFPOperations;
+#endif
+
+#endif // QT_CONFIG(raster_fp)
/*
result = 0
@@ -362,6 +509,17 @@ void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int lengt
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Clear_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32, uint const_alpha)
+{
+ comp_func_Clear_template<RgbaFPOperations>(dest, length, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Clear_rgbafp(QRgbaFloat32 *dest, const QRgbaFloat32 *, int length, uint const_alpha)
+{
+ comp_func_Clear_template<RgbaFPOperations>(dest, length, const_alpha);
+}
+#endif
/*
result = s
@@ -421,6 +579,18 @@ void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Source_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_Source_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Source_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_Source_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint)
{
}
@@ -439,6 +609,16 @@ void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, ui
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Destination_rgbafp(QRgbaFloat32 *, int, QRgbaFloat32, uint)
+{
+}
+
+void QT_FASTCALL comp_func_Destination_rgbafp(QRgbaFloat32 *, const QRgbaFloat32 *, int, uint)
+{
+}
+#endif
+
/*
result = s + d * sia
dest = (s + d * sia) * ca + d * cia
@@ -509,6 +689,19 @@ void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceOver_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_SourceOver_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+
+void QT_FASTCALL comp_func_SourceOver_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceOver_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d + s * dia
dest = (d + s * dia) * ca + d * cia
@@ -570,6 +763,18 @@ void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationOver_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_DestinationOver_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationOver_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationOver_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s * da
dest = s * da * ca + d * cia
@@ -636,6 +841,18 @@ void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceIn_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_SourceIn_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceIn_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceIn_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d * sa
dest = d * sa * ca + d * cia
@@ -697,6 +914,18 @@ void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, co
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationIn_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_DestinationIn_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationIn_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationIn_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s * dia
dest = s * dia * ca + d * cia
@@ -761,6 +990,18 @@ void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceOut_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_SourceOut_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceOut_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceOut_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d * sia
dest = d * sia * ca + d * cia
@@ -822,6 +1063,18 @@ void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, c
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationOut_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_DestinationOut_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationOut_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationOut_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = s*da + d*sia
dest = s*da*ca + d*sia*ca + d *cia
@@ -883,6 +1136,18 @@ void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_SourceAtop_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_SourceAtop_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_SourceAtop_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_SourceAtop_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d*sa + s*dia
dest = d*sa*ca + s*dia*ca + d *cia
@@ -949,6 +1214,18 @@ void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_DestinationAtop_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_DestinationAtop_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_DestinationAtop_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_DestinationAtop_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
result = d*sia + s*dia
dest = d*sia*ca + s*dia*ca + d *cia
@@ -1011,15 +1288,35 @@ void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_XOR_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_XOR_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_XOR_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_XOR_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
struct QFullCoverage {
inline void store(uint *dest, const uint src) const
{
*dest = src;
}
+#if QT_CONFIG(raster_64bit)
inline void store(QRgba64 *dest, const QRgba64 src) const
{
*dest = src;
}
+#endif
+#if QT_CONFIG(raster_fp)
+ inline void store(QRgbaFloat32 *dest, const QRgbaFloat32 src) const
+ {
+ *dest = src;
+ }
+#endif
};
struct QPartialCoverage {
@@ -1029,14 +1326,27 @@ struct QPartialCoverage {
{
}
+ template<typename Op>
+ inline void store_template(typename Op::Type *dest, const typename Op::Type src) const
+ {
+ Op::store(dest, Op::interpolate8bit(Op::convert(src), ca, Op::load(dest), ica));
+ }
inline void store(uint *dest, const uint src) const
{
- *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
+ store_template<Argb32Operations>(dest, src);
}
+#if QT_CONFIG(raster_64bit)
inline void store(QRgba64 *dest, const QRgba64 src) const
{
- *dest = interpolate255(src, ca, *dest, ica);
+ store_template<Rgba64Operations>(dest, src);
+ }
+#endif
+#if QT_CONFIG(raster_fp)
+ inline void store(QRgbaFloat32 *dest, const QRgbaFloat32 src) const
+ {
+ store_template<RgbaFPOperations>(dest, src);
}
+#endif
private:
const uint ca;
@@ -1045,13 +1355,22 @@ private:
static inline int mix_alpha(int da, int sa)
{
- return 255 - ((255 - sa) * (255 - da) >> 8);
+ return 255 - qt_div_255((255 - sa) * (255 - da));
}
+#if QT_CONFIG(raster_64bit)
static inline uint mix_alpha_rgb64(uint da, uint sa)
{
- return 65535 - ((65535 - sa) * (65535 - da) >> 16);
+ return 65535U - qt_div_65535((65535U - sa) * (65535U - da));
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+static inline float mix_alpha_rgbafp(float da, float sa)
+{
+ return 1.0f - (1.0f - sa) * (1.0f - da);
}
+#endif
/*
Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1122,6 +1441,18 @@ void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Plus_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ comp_func_solid_Plus_template<RgbaFPOperations>(dest, length, color, const_alpha);
+}
+
+void QT_FASTCALL comp_func_Plus_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ comp_func_Plus_template<RgbaFPOperations>(dest, src, length, const_alpha);
+}
+#endif
+
/*
Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
*/
@@ -1164,7 +1495,7 @@ void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, ui
#if QT_CONFIG(raster_64bit)
static inline uint multiply_op_rgb64(uint dst, uint src, uint da, uint sa)
{
- return qt_div_65535(src * dst + src * (65535 - da) + dst * (65535 - sa));
+ return qt_div_65535(src * dst + src * (65535U - da) + dst * (65535U - sa));
}
template <typename T>
@@ -1199,6 +1530,45 @@ void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float multiply_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return src * dst + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Multiply_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) multiply_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Multiply_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
+
template <typename T>
static inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1259,6 +1629,37 @@ void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const Q
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Multiply_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) multiply_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Multiply_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Multiply_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - Sca.Dca
@@ -1307,7 +1708,7 @@ static inline void comp_func_solid_Screen_impl(QRgba64 *dest, int length, QRgba6
QRgba64 d = dest[i];
uint da = d.alpha();
-#define OP(a, b) 65535 - qt_div_65535((65535-a) * (65535-b))
+#define OP(a, b) 65535 - qt_div_65535((65535U-a) * (65535U-b))
uint r = OP( d.red(), sr);
uint b = OP( d.blue(), sb);
uint g = OP(d.green(), sg);
@@ -1327,6 +1728,39 @@ void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_solid_Screen_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) (1.0f - ((1.0f - a) * (1.0f - b)))
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Screen_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1337,7 +1771,7 @@ static inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint
int da = qAlpha(d);
int sa = qAlpha(s);
-#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8)
+#define OP(a, b) 255 - qt_div_255((255-a) * (255-b))
int r = OP( qRed(d), qRed(s));
int b = OP( qBlue(d), qBlue(s));
int g = OP(qGreen(d), qGreen(s));
@@ -1367,7 +1801,7 @@ static inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QR
uint da = d.alpha();
uint sa = s.alpha();
-#define OP(a, b) 65535 - (((65535-a) * (65535-b)) >> 16)
+#define OP(a, b) 65535U - qt_div_65535((65535U-a) * (65535U-b))
uint r = OP( d.red(), s.red());
uint b = OP( d.blue(), s.blue());
uint g = OP(d.green(), s.green());
@@ -1387,6 +1821,37 @@ void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int l
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Screen_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) (1.0f - ((1.0f - a) * (1.0f - b)))
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Screen_rgbafp(QRgbaFloat32 *dest, const QRgbaFloat32 *src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Screen_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Dca < Da
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1436,7 +1901,7 @@ void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uin
#if QT_CONFIG(raster_64bit)
static inline uint overlay_op_rgb64(uint dst, uint src, uint da, uint sa)
{
- const uint temp = src * (65535 - da) + dst * (65535 - sa);
+ const uint temp = src * (65535U - da) + dst * (65535U - sa);
if (2 * dst < da)
return qt_div_65535(2 * src * dst + temp);
else
@@ -1475,6 +1940,48 @@ void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float overlay_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+ if (2 * dst < da)
+ return 2 * src * dst + temp;
+ else
+ return sa * da - 2 * (da - dst) * (sa - src) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_Overlay_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) overlay_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Overlay_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1535,6 +2042,37 @@ void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Overlay_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) overlay_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Overlay_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Overlay_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1578,7 +2116,7 @@ void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint
#if QT_CONFIG(raster_64bit)
static inline uint darken_op_rgb64(uint dst, uint src, uint da, uint sa)
{
- return qt_div_65535(qMin(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
+ return qt_div_65535(qMin(src * da, dst * sa) + src * (65535U - da) + dst * (65535U - sa));
}
template <typename T>
@@ -1613,6 +2151,44 @@ void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float darken_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return qMin(src * da, dst * sa) + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Darken_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) darken_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Darken_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1673,6 +2249,37 @@ void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Darken_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) darken_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Darken_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Darken_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1717,7 +2324,7 @@ void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uin
#if QT_CONFIG(raster_64bit)
static inline uint lighten_op_rgb64(uint dst, uint src, uint da, uint sa)
{
- return qt_div_65535(qMax(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
+ return qt_div_65535(qMax(src * da, dst * sa) + src * (65535U - da) + dst * (65535U - sa));
}
template <typename T>
@@ -1752,6 +2359,44 @@ void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba6
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float lighten_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return qMax(src * da, dst * sa) + src * (1.0f - da) + dst * (1.0f - sa);
+}
+
+template <typename T>
+static inline void comp_func_solid_Lighten_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) lighten_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Lighten_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1812,6 +2457,37 @@ void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QR
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Lighten_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) lighten_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Lighten_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Lighten_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if Sca.Da + Dca.Sa > Sa.Da
Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1873,13 +2549,13 @@ static inline uint color_dodge_op_rgb64(qint64 dst, qint64 src, qint64 da, qint6
const qint64 dst_sa = dst * sa;
const qint64 src_da = src * da;
- const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
+ const qint64 temp = src * (65535U - da) + dst * (65535U - sa);
if (src_da + dst_sa > sa_da)
return qt_div_65535(sa_da + temp);
else if (src == sa || sa == 0)
return qt_div_65535(temp);
else
- return qt_div_65535(65535 * dst_sa / (65535 - 65535 * src / sa) + temp);
+ return qt_div_65535(65535U * dst_sa / (65535U - 65535U * src / sa) + temp);
}
template <typename T>
@@ -1914,6 +2590,54 @@ void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float color_dodge_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float sa_da = sa * da;
+ const float dst_sa = dst * sa;
+ const float src_da = src * da;
+
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+ if (src_da + dst_sa > sa_da)
+ return sa_da + temp;
+ else if (src == sa || sa == 0.0f)
+ return temp;
+ else
+ return dst_sa / (1.0f - src / sa) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_ColorDodge_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a,b) color_dodge_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_ColorDodge_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1974,6 +2698,37 @@ void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_ColorDodge_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) color_dodge_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_ColorDodge_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if Sca.Da + Dca.Sa < Sa.Da
Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2035,7 +2790,7 @@ static inline uint color_burn_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64
const qint64 dst_sa = dst * sa;
const qint64 sa_da = sa * da;
- const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
+ const qint64 temp = src * (65535U - da) + dst * (65535U - sa);
if (src_da + dst_sa < sa_da)
return qt_div_65535(temp);
@@ -2076,6 +2831,54 @@ void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float color_burn_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float src_da = src * da;
+ const float dst_sa = dst * sa;
+ const float sa_da = sa * da;
+
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (src_da + dst_sa < sa_da)
+ return temp;
+ else if (src == 0)
+ return dst_sa + temp;
+ return sa * (src_da + dst_sa - sa_da) / src + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_ColorBurn_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) color_burn_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_ColorBurn_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2136,6 +2939,37 @@ void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_ColorBurn_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) color_burn_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_ColorBurn_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Sca < Sa
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2186,7 +3020,7 @@ void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, u
#if QT_CONFIG(raster_64bit)
static inline uint hardlight_op_rgb64(uint dst, uint src, uint da, uint sa)
{
- const uint temp = src * (65535 - da) + dst * (65535 - sa);
+ const uint temp = src * (65535U - da) + dst * (65535U - sa);
if (2 * src < sa)
return qt_div_65535(2 * src * dst + temp);
@@ -2226,6 +3060,49 @@ void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float hardlight_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (2 * src < sa)
+ return 2 * src * dst + temp;
+ else
+ return sa * da - 2 * (da - dst) * (sa - src) + temp;
+}
+
+template <typename T>
+static inline void comp_func_solid_HardLight_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) hardlight_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_HardLight_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2286,6 +3163,37 @@ void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_HardLight_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) hardlight_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_HardLight_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_HardLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
if 2.Sca <= Sa
Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -2332,20 +3240,28 @@ static inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint c
}
}
+void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
#if QT_CONFIG(raster_64bit)
static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
{
const qint64 src2 = src << 1;
- const qint64 dst_np = da != 0 ? (65535 * dst) / da : 0;
- const qint64 temp = (src * (65535 - da) + dst * (65535 - sa)) * 65535;
- const qint64 factor = qint64(65535) * 65535;
+ const qint64 dst_np = da != 0 ? (65535U * dst) / da : 0;
+ const qint64 temp = (src * (65535U - da) + dst * (65535U - sa)) * 65535U;
+ const qint64 factor = Q_UINT64_C(65535) * 65535U;
if (src2 < sa)
- return (dst * (sa * 65535 + (src2 - sa) * (65535 - dst_np)) + temp) / factor;
+ return (dst * (sa * 65535U + (src2 - sa) * (65535U - dst_np)) + temp) / factor;
else if (4 * dst <= da)
- return (dst * sa * 65535 + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor;
+ return (dst * sa * 65535U + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535U) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor;
else {
- return (dst * sa * 65535 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535))) - dst_np) + temp) / factor;
+ return (dst * sa * 65535U + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535U))) - dst_np) + temp) / factor;
}
}
@@ -2371,15 +3287,64 @@ static inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRg
coverage.store(&dest[i], qRgba64(r, g, b, a));
}
}
+
+void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
#endif
-void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
+#if QT_CONFIG(raster_fp)
+static inline float soft_light_op_rgbafp(float dst, float src, float da, float sa)
+{
+ const float src2 = src * 2;
+ const float dst_np = da != 0.0f ? (dst / da) : 0.0f;
+ const float temp = src * (1.0f - da) + dst * (1.0f - sa);
+
+ if (src2 < sa)
+ return dst * (sa + (src2 - sa) * (1.0f - dst_np)) + temp;
+ else if (4 * dst <= da)
+ return dst * sa + da * (src2 - sa) * (((16 * dst_np - 12) * dst_np + 3) * dst_np) + temp;
+ else {
+ return dst * sa + da * (src2 - sa) * (qSqrt(qreal(dst_np)) - dst_np) + temp;
+ }
+}
+
+template <typename T>
+static inline void comp_func_solid_SoftLight_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) soft_light_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_SoftLight_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
{
if (const_alpha == 255)
comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
else
comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+#endif
template <typename T>
static inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
@@ -2411,14 +3376,6 @@ void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_D
}
#if QT_CONFIG(raster_64bit)
-void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
-{
- if (const_alpha == 255)
- comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
- else
- comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
-}
-
template <typename T>
static inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2449,6 +3406,37 @@ void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_SoftLight_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) soft_light_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_SoftLight_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - 2.min(Sca.Da, Dca.Sa)
@@ -2527,6 +3515,44 @@ void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRg
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline float difference_op_rgbafp(float dst, float src, float da, float sa)
+{
+ return src + dst - (2 * qMin(src * da, dst * sa));
+}
+
+template <typename T>
+static inline void comp_func_solid_Difference_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) difference_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Difference_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2587,6 +3613,37 @@ void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Difference_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) difference_op_rgbafp(a, b, da, sa)
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Difference_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Difference_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
/*
Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
*/
@@ -2645,7 +3702,6 @@ static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba64 *dest, int
}
}
-
void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
{
if (const_alpha == 255)
@@ -2655,6 +3711,39 @@ void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgb
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, const T &coverage)
+{
+ float sa = color.alpha();
+ float sr = color.red();
+ float sg = color.green();
+ float sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ float da = d.alpha();
+
+#define OP(a, b) (a + b - (2.0f * a * b))
+ float r = OP( d.red(), sr);
+ float b = OP( d.blue(), sb);
+ float g = OP(d.green(), sg);
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_solid_Exclusion_rgbafp(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+#endif
+
template <typename T>
static inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -2715,6 +3804,37 @@ void QT_FASTCALL comp_func_Exclusion_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const
}
#endif
+#if QT_CONFIG(raster_fp)
+template <typename T>
+static inline void comp_func_Exclusion_impl(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgbaFloat32 d = dest[i];
+ QRgbaFloat32 s = src[i];
+
+ float da = d.alpha();
+ float sa = s.alpha();
+
+#define OP(a, b) (a + b - (2.0f * a * b))
+ float r = OP( d.red(), s.red());
+ float b = OP( d.blue(), s.blue());
+ float g = OP(d.green(), s.green());
+ float a = mix_alpha_rgbafp(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgbaFloat32(r, g, b, a));
+ }
+}
+
+void QT_FASTCALL comp_func_Exclusion_rgbafp(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+#endif
+
void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
int length,
uint color,
@@ -3089,6 +4209,41 @@ CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = {
comp_func_solid_Difference_rgb64,
comp_func_solid_Exclusion_rgb64,
#else
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+#endif
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+};
+
+CompositionFunctionSolidFP qt_functionForModeSolidFP_C[] = {
+#if QT_CONFIG(raster_fp)
+ comp_func_solid_SourceOver_rgbafp,
+ comp_func_solid_DestinationOver_rgbafp,
+ comp_func_solid_Clear_rgbafp,
+ comp_func_solid_Source_rgbafp,
+ comp_func_solid_Destination_rgbafp,
+ comp_func_solid_SourceIn_rgbafp,
+ comp_func_solid_DestinationIn_rgbafp,
+ comp_func_solid_SourceOut_rgbafp,
+ comp_func_solid_DestinationOut_rgbafp,
+ comp_func_solid_SourceAtop_rgbafp,
+ comp_func_solid_DestinationAtop_rgbafp,
+ comp_func_solid_XOR_rgbafp,
+ comp_func_solid_Plus_rgbafp,
+ comp_func_solid_Multiply_rgbafp,
+ comp_func_solid_Screen_rgbafp,
+ comp_func_solid_Overlay_rgbafp,
+ comp_func_solid_Darken_rgbafp,
+ comp_func_solid_Lighten_rgbafp,
+ comp_func_solid_ColorDodge_rgbafp,
+ comp_func_solid_ColorBurn_rgbafp,
+ comp_func_solid_HardLight_rgbafp,
+ comp_func_solid_SoftLight_rgbafp,
+ comp_func_solid_Difference_rgbafp,
+ comp_func_solid_Exclusion_rgbafp,
+#else
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
@@ -3164,6 +4319,41 @@ CompositionFunction64 qt_functionForMode64_C[] = {
comp_func_Difference_rgb64,
comp_func_Exclusion_rgb64,
#else
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+#endif
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
+};
+
+CompositionFunctionFP qt_functionForModeFP_C[] = {
+#if QT_CONFIG(raster_fp)
+ comp_func_SourceOver_rgbafp,
+ comp_func_DestinationOver_rgbafp,
+ comp_func_Clear_rgbafp,
+ comp_func_Source_rgbafp,
+ comp_func_Destination_rgbafp,
+ comp_func_SourceIn_rgbafp,
+ comp_func_DestinationIn_rgbafp,
+ comp_func_SourceOut_rgbafp,
+ comp_func_DestinationOut_rgbafp,
+ comp_func_SourceAtop_rgbafp,
+ comp_func_DestinationAtop_rgbafp,
+ comp_func_XOR_rgbafp,
+ comp_func_Plus_rgbafp,
+ comp_func_Multiply_rgbafp,
+ comp_func_Screen_rgbafp,
+ comp_func_Overlay_rgbafp,
+ comp_func_Darken_rgbafp,
+ comp_func_Lighten_rgbafp,
+ comp_func_ColorDodge_rgbafp,
+ comp_func_ColorBurn_rgbafp,
+ comp_func_HardLight_rgbafp,
+ comp_func_SoftLight_rgbafp,
+ comp_func_Difference_rgbafp,
+ comp_func_Exclusion_rgbafp,
+#else
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index 0030e8e29c..27b46202f5 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcoregraphics_p.h"
@@ -58,22 +22,22 @@ CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image)
CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
switch (image.format()) {
case QImage::Format_ARGB32:
- bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaFirst) | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGB32:
- bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipFirst) | kCGBitmapByteOrder32Host;
break;
case QImage::Format_RGBA8888_Premultiplied:
- bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedLast) | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBA8888:
- bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaLast) | kCGBitmapByteOrder32Big;
break;
case QImage::Format_RGBX8888:
- bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipLast) | kCGBitmapByteOrder32Big;
break;
case QImage::Format_ARGB32_Premultiplied:
- bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
+ bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedFirst) | kCGBitmapByteOrder32Host;
break;
default: break;
}
@@ -145,7 +109,7 @@ QT_END_NAMESPACE
// NSImage.
auto nsImage = [[NSImage alloc] initWithSize:NSZeroSize];
auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
- imageRep.size = (image.size() / image.devicePixelRatioF()).toCGSize();
+ imageRep.size = image.deviceIndependentSize().toCGSize();
[nsImage addRepresentation:[imageRep autorelease]];
Q_ASSERT(CGSizeEqualToSize(nsImage.size, imageRep.size));
@@ -168,7 +132,7 @@ QT_END_NAMESPACE
auto nsImage = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease];
- for (QSize size : qAsConst(availableSizes)) {
+ for (QSize size : std::as_const(availableSizes)) {
QImage image = icon.pixmap(size).toImage();
if (image.isNull())
continue;
@@ -178,7 +142,7 @@ QT_END_NAMESPACE
continue;
auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
- imageRep.size = (image.size() / image.devicePixelRatioF()).toCGSize();
+ imageRep.size = image.deviceIndependentSize().toCGSize();
[nsImage addRepresentation:[imageRep autorelease]];
}
@@ -198,6 +162,9 @@ QT_BEGIN_NAMESPACE
QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
{
+ // ### TODO: add parameter so that we can decide whether to maintain the aspect
+ // ratio of the image (positioning the image inside the pixmap of size \a size),
+ // or whether we want to fill the resulting pixmap by stretching the image.
const NSSize pixmapSize = NSMakeSize(size.width(), size.height());
QPixmap pixmap(pixmapSize.width, pixmapSize.height);
pixmap.fill(Qt::transparent);
@@ -218,6 +185,25 @@ QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
#endif // Q_OS_MACOS
+#ifdef QT_PLATFORM_UIKIT
+
+QImage qt_mac_toQImage(const UIImage *image, QSizeF size)
+{
+ // ### TODO: same as above
+ QImage ret(size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
+ ret.fill(Qt::transparent);
+ QMacCGContext ctx(&ret);
+ if (!ctx)
+ return QImage();
+ UIGraphicsPushContext(ctx);
+ const CGRect rect = CGRectMake(0, 0, size.width(), size.height());
+ [image drawInRect:rect];
+ UIGraphicsPopContext();
+ return ret;
+}
+
+#endif // QT_PLATFORM_UIKIT
+
// ---------------------- Colors and Brushes ----------------------
QColor qt_mac_toQColor(CGColorRef color)
@@ -422,11 +408,14 @@ void QMacCGContext::initialize(QPaintDevice *paintDevice)
// Find the underlying QImage of the paint device
switch (int deviceType = paintDevice->devType()) {
case QInternal::Pixmap: {
- auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle();
- if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass)
- initialize(platformPixmap->buffer());
- else
- qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
+ if (auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle()) {
+ if (platformPixmap->classId() == QPlatformPixmap::RasterClass)
+ initialize(platformPixmap->buffer());
+ else
+ qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
+ } else {
+ qWarning() << "QMacCGContext: Empty platformPixmap";
+ }
break;
}
case QInternal::Image:
@@ -510,7 +499,7 @@ void QMacCGContext::initialize(const QImage *image, QPainter *painter)
clip &= painterClip;
}
- qt_mac_clip_cg(context, clip, 0);
+ qt_mac_clip_cg(context, clip, nullptr);
CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy());
}
diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h
index db012d3cda..a35f27a730 100644
--- a/src/gui/painting/qcoregraphics_p.h
+++ b/src/gui/painting/qcoregraphics_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOREGRAPHICS_P_H
#define QCOREGRAPHICS_P_H
@@ -59,19 +23,31 @@
#include <CoreGraphics/CoreGraphics.h>
-#if defined(__OBJC__) && defined(Q_OS_MACOS)
-#include <AppKit/AppKit.h>
-#define HAVE_APPKIT
+#if defined(__OBJC__)
+# if defined(Q_OS_MACOS)
+# include <AppKit/AppKit.h>
+# elif defined(QT_PLATFORM_UIKIT)
+# include <UIKit/UIKit.h>
+# endif
#endif
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image);
-#ifdef HAVE_APPKIT
+#ifdef QT_PLATFORM_UIKIT
+Q_GUI_EXPORT QImage qt_mac_toQImage(const UIImage *image, QSizeF size);
+#endif
+
+#ifdef Q_OS_MACOS
Q_GUI_EXPORT QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size);
QT_END_NAMESPACE
+
+// @compatibility_alias doesn't work with categories or their methods
+#define imageFromQImage QT_MANGLE_NAMESPACE(imageFromQImage)
+#define imageFromQIcon QT_MANGLE_NAMESPACE(imageFromQIcon)
+
@interface NSImage (QtExtras)
+ (instancetype)imageFromQImage:(const QT_PREPEND_NAMESPACE(QImage) &)image;
+ (instancetype)imageFromQIcon:(const QT_PREPEND_NAMESPACE(QIcon) &)icon;
@@ -88,7 +64,7 @@ Q_GUI_EXPORT void qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBou
Q_GUI_EXPORT void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform);
-#ifdef HAVE_APPKIT
+#ifdef Q_OS_MACOS
Q_GUI_EXPORT QColor qt_mac_toQColor(const NSColor *color);
Q_GUI_EXPORT QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup = QPalette::Normal);
#endif
@@ -112,6 +88,4 @@ private:
QT_END_NAMESPACE
-#undef HAVE_APPKIT
-
#endif // QCOREGRAPHICS_P_H
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index 9012119516..a0eddf65d9 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcosmeticstroker_p.h"
#include "private/qpainterpath_p.h"
@@ -58,18 +22,28 @@ inline QString capString(int caps)
}
#endif
-#define toF26Dot6(x) ((int)((x)*64.))
+#if Q_PROCESSOR_WORDSIZE == 8
+typedef qint64 FDot16;
+#else
+typedef int FDot16;
+#endif
+
+#define toF26Dot6(x) static_cast<int>((x) * 64.)
static inline uint sourceOver(uint d, uint color)
{
return color + BYTE_MUL(d, qAlpha(~color));
}
-inline static int F16Dot16FixedDiv(int x, int y)
+inline static FDot16 FDot16FixedDiv(int x, int y)
{
+#if Q_PROCESSOR_WORDSIZE == 8
+ return FDot16(x) * (1<<16) / y;
+#else
if (qAbs(x) > 0x7fff)
- return qlonglong(x) * (1<<16) / y;
+ return static_cast<qlonglong>(x) * (1<<16) / y;
return x * (1<<16) / y;
+#endif
}
typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
@@ -101,7 +75,7 @@ struct Dasher {
offset += stroker->patternLength;
dashIndex = 0;
- while (offset>= pattern[dashIndex])
+ while (dashIndex < stroker->patternSize - 1 && offset>= pattern[dashIndex])
++dashIndex;
// qDebug() << " dasher" << offset/64. << reverse << dashIndex;
@@ -157,7 +131,7 @@ inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
}
}
- stroker->spans[stroker->current_span].x = ushort(x);
+ stroker->spans[stroker->current_span].x = x;
stroker->spans[stroker->current_span].len = 1;
stroker->spans[stroker->current_span].y = y;
stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
@@ -249,26 +223,26 @@ void QCosmeticStroker::setup()
if (state->renderHints & QPainter::Antialiasing)
strokeSelection |= AntiAliased;
- const QVector<qreal> &penPattern = state->lastPen.dashPattern();
- if (penPattern.isEmpty()) {
+ const QList<qreal> &penPattern = state->lastPen.dashPattern();
+ if (penPattern.isEmpty() || penPattern.size() > 1024) {
Q_ASSERT(!pattern && !reversePattern);
pattern = nullptr;
reversePattern = nullptr;
patternLength = 0;
patternSize = 0;
} else {
- pattern = (int *)malloc(penPattern.size()*sizeof(int));
- reversePattern = (int *)malloc(penPattern.size()*sizeof(int));
+ pattern = static_cast<int *>(malloc(penPattern.size() * sizeof(int)));
+ reversePattern = static_cast<int *>(malloc(penPattern.size() * sizeof(int)));
patternSize = penPattern.size();
patternLength = 0;
for (int i = 0; i < patternSize; ++i) {
- patternLength += (int) qMax(1. , penPattern.at(i)*64.);
+ patternLength += static_cast<int>(qBound(1., penPattern.at(i) * 64, 65536.));
pattern[i] = patternLength;
}
patternLength = 0;
for (int i = 0; i < patternSize; ++i) {
- patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
+ patternLength += static_cast<int>(qBound(1., penPattern.at(patternSize - 1 - i) * 64, 65536.));
reversePattern[i] = patternLength;
}
strokeSelection |= Dashed;
@@ -280,18 +254,18 @@ void QCosmeticStroker::setup()
qreal width = state->lastPen.widthF();
if (width == 0)
opacity = 256;
- else if (qt_pen_is_cosmetic(state->lastPen, state->renderHints))
- opacity = (int) 256*width;
+ else if (state->lastPen.isCosmetic())
+ opacity = static_cast<int>(256 * width);
else
- opacity = (int) 256*width*state->txscale;
+ opacity = static_cast<int>(256 * width * state->txscale);
opacity = qBound(0, opacity, 256);
drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
if (strokeSelection & FastDraw) {
- color = multiplyAlpha256(state->penData.solidColor, opacity).toArgb32();
+ color = multiplyAlpha256(state->penData.solidColor.rgba64(), opacity).toArgb32();
QRasterBuffer *buffer = state->penData.rasterBuffer;
- pixels = (uint *)buffer->buffer();
+ pixels = reinterpret_cast<uint *>(buffer->buffer());
ppl = buffer->stride<quint32>();
}
@@ -311,6 +285,8 @@ void QCosmeticStroker::setup()
// returns true if the whole line gets clipped away
bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
{
+ if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
+ return true;
// basic/rough clipping is done in floating point coordinates to avoid
// integer overflow problems.
if (x1 < xmin) {
@@ -365,14 +341,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;
@@ -388,7 +364,7 @@ void QCosmeticStroker::drawPoints(const QPoint *points, int num)
const QPoint *end = points + num;
while (points < end) {
QPointF p = QPointF(*points) * state->matrix;
- drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ drawPixel(this, std::floor(p.x()), std::floor(p.y()), 255);
++points;
}
@@ -401,7 +377,7 @@ void QCosmeticStroker::drawPoints(const QPointF *points, int num)
const QPointF *end = points + num;
while (points < end) {
QPointF p = (*points) * state->matrix;
- drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ drawPixel(this, std::floor(p.x()), std::floor(p.y()), 255);
++points;
}
@@ -424,11 +400,10 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
if (clipLine(rx1, ry1, rx2, ry2))
return;
- const int half = legacyRounding ? 31 : 0;
- int x1 = toF26Dot6(rx1) + half;
- int y1 = toF26Dot6(ry1) + half;
- int x2 = toF26Dot6(rx2) + half;
- int y2 = toF26Dot6(ry2) + half;
+ int x1 = toF26Dot6(rx1);
+ int y1 = toF26Dot6(ry1);
+ int x2 = toF26Dot6(rx2);
+ int y2 = toF26Dot6(ry2);
int dx = qAbs(x2 - x1);
int dy = qAbs(y2 - y1);
@@ -441,8 +416,8 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
qSwap(y1, y2);
qSwap(x1, x2);
}
- int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
- int x = x1 * (1<<10);
+ FDot16 xinc = FDot16FixedDiv(x2 - x1, y2 - y1);
+ FDot16 x = FDot16(x1) * (1<<10);
int y = (y1 + 32) >> 6;
int ys = (y2 + 32) >> 6;
@@ -473,8 +448,8 @@ void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal
qSwap(x1, x2);
qSwap(y1, y2);
}
- int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
- int y = y1 << 10;
+ FDot16 yinc = FDot16FixedDiv(y2 - y1, x2 - x1);
+ FDot16 y = FDot16(y1) * (1 << 10);
int x = (x1 + 32) >> 6;
int xs = (x2 + 32) >> 6;
@@ -692,7 +667,7 @@ void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points,
if (level) {
qreal dx = points[3].x - points[0].x;
qreal dy = points[3].y - points[0].y;
- qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy));
+ qreal len = static_cast<qreal>(.25) * (qAbs(dx) + qAbs(dy));
if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
@@ -715,7 +690,7 @@ static inline int swapCaps(int caps)
}
// adjust line by half a pixel
-static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
+static inline void capAdjust(int caps, int &x1, int &x2, FDot16 &y, FDot16 yinc)
{
if (caps & QCosmeticStroker::CapBegin) {
x1 -= 32;
@@ -738,11 +713,10 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
if (stroker->clipLine(rx1, ry1, rx2, ry2))
return true;
- const int half = stroker->legacyRounding ? 31 : 0;
- int x1 = toF26Dot6(rx1) + half;
- int y1 = toF26Dot6(ry1) + half;
- int x2 = toF26Dot6(rx2) + half;
- int y2 = toF26Dot6(ry2) + half;
+ int x1 = toF26Dot6(rx1);
+ int y1 = toF26Dot6(ry1);
+ int x2 = toF26Dot6(rx2);
+ int y2 = toF26Dot6(ry2);
int dx = qAbs(x2 - x1);
int dy = qAbs(y2 - y1);
@@ -763,8 +737,8 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
caps = swapCaps(caps);
dir = QCosmeticStroker::BottomToTop;
}
- int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
- int x = x1 * (1<<10);
+ FDot16 xinc = FDot16FixedDiv(x2 - x1, y2 - y1);
+ FDot16 x = FDot16(x1) * (1<<10);
if ((stroker->lastDir ^ QCosmeticStroker::VerticalMask) == dir)
caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
@@ -853,8 +827,8 @@ static bool drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2,
caps = swapCaps(caps);
dir = QCosmeticStroker::RightToLeft;
}
- int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
- int y = y1 * (1<<10);
+ FDot16 yinc = FDot16FixedDiv(y2 - y1, x2 - x1);
+ FDot16 y = FDot16(y1) * (1<<10);
if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
@@ -950,7 +924,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
if (qAbs(dx) < qAbs(dy)) {
// vertical
- int xinc = F16Dot16FixedDiv(dx, dy);
+ FDot16 xinc = FDot16FixedDiv(dx, dy);
bool swapped = false;
if (y1 > y2) {
@@ -960,7 +934,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
caps = swapCaps(caps);
}
- int x = (x1 - 32) * (1<<10);
+ FDot16 x = FDot16(x1 - 32) * (1<<10);
x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
capAdjust(caps, y1, y2, x, xinc);
@@ -984,7 +958,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
// draw first pixel
if (dasher.on()) {
- uint alpha = (quint8)(x >> 8);
+ uint alpha = static_cast<quint8>(x >> 8);
drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
}
@@ -994,7 +968,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
if (y < ys) {
do {
if (dasher.on()) {
- uint alpha = (quint8)(x >> 8);
+ uint alpha = static_cast<quint8>(x >> 8);
drawPixel(stroker, x>>16, y, (255-alpha));
drawPixel(stroker, (x>>16) + 1, y, alpha);
}
@@ -1004,7 +978,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
}
// draw last pixel
if (alphaEnd && dasher.on()) {
- uint alpha = (quint8)(x >> 8);
+ uint alpha = static_cast<quint8>(x >> 8);
drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
}
@@ -1013,7 +987,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
if (!dx)
return true;
- int yinc = F16Dot16FixedDiv(dy, dx);
+ FDot16 yinc = FDot16FixedDiv(dy, dx);
bool swapped = false;
if (x1 > x2) {
@@ -1023,7 +997,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
caps = swapCaps(caps);
}
- int y = (y1 - 32) * (1<<10);
+ FDot16 y = FDot16(y1 - 32) * (1<<10);
y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
capAdjust(caps, x1, x2, y, yinc);
@@ -1047,7 +1021,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
// draw first pixel
if (dasher.on()) {
- uint alpha = (quint8)(y >> 8);
+ uint alpha = static_cast<quint8>(y >> 8);
drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
}
@@ -1058,7 +1032,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
if (x < xs) {
do {
if (dasher.on()) {
- uint alpha = (quint8)(y >> 8);
+ uint alpha = static_cast<quint8>(y >> 8);
drawPixel(stroker, x, y>>16, (255-alpha));
drawPixel(stroker, x, (y>>16) + 1, alpha);
}
@@ -1068,7 +1042,7 @@ static bool drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx
}
// draw last pixel
if (alphaEnd && dasher.on()) {
- uint alpha = (quint8)(y >> 8);
+ uint alpha = static_cast<quint8>(y >> 8);
drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);
}
diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h
index 8571b0476a..cb31ae4b71 100644
--- a/src/gui/painting/qcosmeticstroker_p.h
+++ b/src/gui/painting/qcosmeticstroker_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOSMETICSTROKER_P_H
#define QCOSMETICSTROKER_P_H
@@ -103,7 +67,6 @@ public:
patternSize(0),
patternLength(0),
patternOffset(0),
- legacyRounding(false),
current_span(0),
lastDir(NoDirection),
lastAxisAligned(false)
@@ -111,8 +74,6 @@ public:
~QCosmeticStroker() { free(pattern); free(reversePattern); }
- void setLegacyRoundingEnabled(bool legacyRoundingEnabled) { legacyRounding = legacyRoundingEnabled; }
-
void drawLine(const QPointF &p1, const QPointF &p2);
void drawPath(const QVectorPath &path);
void drawPoints(const QPoint *points, int num);
@@ -135,8 +96,6 @@ public:
int patternLength;
int patternOffset;
- bool legacyRounding;
-
enum { NSPANS = 255 };
QT_FT_Span spans[NSPANS];
int current_span;
diff --git a/src/gui/painting/qcssutil.cpp b/src/gui/painting/qcssutil.cpp
index 2d514e14e0..caface7d1a 100644
--- a/src/gui/painting/qcssutil.cpp
+++ b/src/gui/painting/qcssutil.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcssutil_p.h"
#include "private/qcssparser_p.h"
@@ -204,28 +168,28 @@ void qDrawEdge(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2, qreal dw1, q
if (width == 1 || (dw1 == 0 && dw2 == 0)) {
p->drawRect(QRectF(x1, y1, x2-x1, y2-y1));
} else { // draw trapezoid
- QPolygonF quad;
+ std::array<QPointF, 4> quad;
switch (edge) {
case TopEdge:
- quad << QPointF(x1, y1) << QPointF(x1 + dw1, y2)
- << QPointF(x2 - dw2, y2) << QPointF(x2, y1);
+ quad = {QPointF(x1, y1), QPointF(x1 + dw1, y2),
+ QPointF(x2 - dw2, y2), QPointF(x2, y1)};
break;
case BottomEdge:
- quad << QPointF(x1 + dw1, y1) << QPointF(x1, y2)
- << QPointF(x2, y2) << QPointF(x2 - dw2, y1);
+ quad = {QPointF(x1 + dw1, y1), QPointF(x1, y2),
+ QPointF(x2, y2), QPointF(x2 - dw2, y1)};
break;
case LeftEdge:
- quad << QPointF(x1, y1) << QPointF(x1, y2)
- << QPointF(x2, y2 - dw2) << QPointF(x2, y1 + dw1);
+ quad = {QPointF(x1, y1), QPointF(x1, y2),
+ QPointF(x2, y2 - dw2), QPointF(x2, y1 + dw1)};
break;
case RightEdge:
- quad << QPointF(x1, y1 + dw1) << QPointF(x1, y2 - dw2)
- << QPointF(x2, y2) << QPointF(x2, y1);
+ quad = {QPointF(x1, y1 + dw1), QPointF(x1, y2 - dw2),
+ QPointF(x2, y2), QPointF(x2, y1)};
break;
default:
break;
}
- p->drawConvexPolygon(quad);
+ p->drawConvexPolygon(quad.data(), static_cast<int>(quad.size()));
}
break;
}
@@ -304,6 +268,7 @@ void qDrawEdge(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2, qreal dw1, q
default:
break;
}
+ break;
}
default:
break;
@@ -328,7 +293,7 @@ void qNormalizeRadii(const QRect &br, const QSize *radii,
*trr = *brr = QSize(0, 0);
}
-// Determines if Edge e1 draws over Edge e2. Depending on this trapezoids or rectanges are drawn
+// Determines if Edge e1 draws over Edge e2. Depending on this trapezoids or rectangles are drawn
static bool paintsOver(const QCss::BorderStyle *styles, const QBrush *colors, QCss::Edge e1, QCss::Edge e2)
{
QCss::BorderStyle s1 = styles[e1];
@@ -352,7 +317,7 @@ void qDrawBorder(QPainter *p, const QRect &rect, const QCss::BorderStyle *styles
QSize tlr, trr, blr, brr;
qNormalizeRadii(rect, radii, &tlr, &trr, &blr, &brr);
- // Drawn in increasing order of precendence
+ // Drawn in increasing order of precedence
if (styles[BottomEdge] != BorderStyle_None && borders[BottomEdge] > 0) {
qreal dw1 = (blr.width() || paintsOver(styles, colors, BottomEdge, LeftEdge)) ? 0 : borders[LeftEdge];
qreal dw2 = (brr.width() || paintsOver(styles, colors, BottomEdge, RightEdge)) ? 0 : borders[RightEdge];
diff --git a/src/gui/painting/qcssutil_p.h b/src/gui/painting/qcssutil_p.h
index 3184b7fa22..34cb5170c1 100644
--- a/src/gui/painting/qcssutil_p.h
+++ b/src/gui/painting/qcssutil_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCSSUTIL_P_H
#define QCSSUTIL_P_H
diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h
index 676750b716..8f467afe4e 100644
--- a/src/gui/painting/qdatabuffer_p.h
+++ b/src/gui/painting/qdatabuffer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDATABUFFER_P_H
#define QDATABUFFER_P_H
@@ -62,11 +26,14 @@ template <typename Type> class QDataBuffer
{
Q_DISABLE_COPY_MOVE(QDataBuffer)
public:
- QDataBuffer(int res)
+ explicit QDataBuffer(qsizetype res)
{
capacity = res;
if (res) {
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Walloc-size-larger-than=")
buffer = (Type*) malloc(capacity * sizeof(Type));
+ QT_WARNING_POP
Q_CHECK_PTR(buffer);
} else {
buffer = nullptr;
@@ -84,11 +51,11 @@ public:
inline bool isEmpty() const { return siz==0; }
- inline int size() const { return siz; }
+ qsizetype size() const { return siz; }
inline Type *data() const { return buffer; }
- inline Type &at(int i) { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; }
- inline const Type &at(int i) const { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; }
+ Type &at(qsizetype i) { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; }
+ const Type &at(qsizetype i) const { Q_ASSERT(i >= 0 && i < siz); return buffer[i]; }
inline Type &last() { Q_ASSERT(!isEmpty()); return buffer[siz-1]; }
inline const Type &last() const { Q_ASSERT(!isEmpty()); return buffer[siz-1]; }
inline Type &first() { Q_ASSERT(!isEmpty()); return buffer[0]; }
@@ -105,12 +72,12 @@ public:
--siz;
}
- inline void resize(int size) {
+ void resize(qsizetype size) {
reserve(size);
siz = size;
}
- inline void reserve(int size) {
+ void reserve(qsizetype size) {
if (size > capacity) {
if (capacity == 0)
capacity = 1;
@@ -121,14 +88,17 @@ public:
}
}
- inline void shrink(int size) {
+ void shrink(qsizetype size) {
+ Q_ASSERT(capacity >= size);
capacity = size;
if (size) {
buffer = (Type*) realloc(static_cast<void*>(buffer), capacity * sizeof(Type));
Q_CHECK_PTR(buffer);
+ siz = std::min(siz, size);
} else {
free(buffer);
buffer = nullptr;
+ siz = 0;
}
}
@@ -141,8 +111,8 @@ public:
inline QDataBuffer &operator<<(const Type &t) { add(t); return *this; }
private:
- int capacity;
- int siz;
+ qsizetype capacity;
+ qsizetype siz;
Type *buffer;
};
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 10aa78ba22..b7a943be38 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -1,48 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qglobal.h>
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdrawhelper_p.h"
#include <qstylehints.h>
#include <qguiapplication.h>
#include <qatomic.h>
+#include <private/qcolortransform_p.h>
#include <private/qcolortrclut_p.h>
#include <private/qdrawhelper_p.h>
#include <private/qdrawhelper_x86_p.h>
@@ -60,6 +25,16 @@
#include <qloggingcategory.h>
#include <qmath.h>
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+#define QT_USE_THREAD_PARALLEL_FILLS
+#endif
+
+#if defined(QT_USE_THREAD_PARALLEL_FILLS)
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQtGuiDrawHelper, "qt.gui.drawhelper")
@@ -70,21 +45,263 @@ Q_LOGGING_CATEGORY(lcQtGuiDrawHelper, "qt.gui.drawhelper")
constants and structures
*/
-enum {
- fixed_scale = 1 << 16,
- half_point = 1 << 15
+constexpr int fixed_scale = 1 << 16;
+constexpr int half_point = 1 << 15;
+
+template <QPixelLayout::BPP bpp> static
+inline uint QT_FASTCALL fetch1Pixel(const uchar *, int)
+{
+ Q_UNREACHABLE_RETURN(0);
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (~index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP8>(const uchar *src, int index)
+{
+ return src[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP16>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint16 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP24>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint24 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32>(const uchar *src, int index)
+{
+ return reinterpret_cast<const uint *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP64>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgbaFloat16 c = reinterpret_cast<const QRgbaFloat16 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgbaFloat32 c = reinterpret_cast<const QRgbaFloat32 *>(src)[index];
+ return c.toArgb32();
+}
+
+typedef uint (QT_FASTCALL *Fetch1PixelFunc)(const uchar *src, int index);
+
+constexpr Fetch1PixelFunc fetch1PixelTable[QPixelLayout::BPPCount] = {
+ nullptr, // BPPNone
+ fetch1Pixel<QPixelLayout::BPP1MSB>,
+ fetch1Pixel<QPixelLayout::BPP1LSB>,
+ fetch1Pixel<QPixelLayout::BPP8>,
+ fetch1Pixel<QPixelLayout::BPP16>,
+ fetch1Pixel<QPixelLayout::BPP24>,
+ fetch1Pixel<QPixelLayout::BPP32>,
+ fetch1Pixel<QPixelLayout::BPP64>,
+ fetch1Pixel<QPixelLayout::BPP16FPx4>,
+ fetch1Pixel<QPixelLayout::BPP32FPx4>,
};
#if QT_CONFIG(raster_64bit)
-static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
+static void QT_FASTCALL convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
{
for (int i = 0; i < count; ++i)
buffer[i] = buffer[i].premultiplied();
}
-static void convertRGBA64PMToRGBA64PM(QRgba64 *, int)
+static void QT_FASTCALL convertRGBA64PMToRGBA64PM(QRgba64 *, int)
{
}
+
+static void QT_FASTCALL convertRGBA16FToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgbaFloat16 *in = reinterpret_cast<const QRgbaFloat16 *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat16 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA16FPMToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgbaFloat16 *in = reinterpret_cast<const QRgbaFloat16 *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat16 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+}
+
+static void QT_FASTCALL convertRGBA32FToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgbaFloat32 *in = reinterpret_cast<const QRgbaFloat32 *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat32 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA32FPMToRGBA64PM(QRgba64 *buffer, int count)
+{
+ const QRgbaFloat32 *in = reinterpret_cast<const QRgbaFloat32 *>(buffer);
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat32 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+}
+
+static Convert64Func convert64ToRGBA64PM[] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertRGBA64PMToRGBA64PM,
+ convertRGBA64ToRGBA64PM,
+ convertRGBA64PMToRGBA64PM,
+ nullptr,
+ nullptr,
+ convertRGBA16FPMToRGBA64PM,
+ convertRGBA16FToRGBA64PM,
+ convertRGBA16FPMToRGBA64PM,
+ convertRGBA32FPMToRGBA64PM,
+ convertRGBA32FToRGBA64PM,
+ convertRGBA32FPMToRGBA64PM,
+ nullptr,
+};
+
+static_assert(std::size(convert64ToRGBA64PM) == QImage::NImageFormats);
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL convertRGBA64PMToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
+{
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
+ for (int i = 0; i < count; ++i) {
+ auto c = in[i];
+ buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), c.alpha()).premultiplied();
+ }
+}
+
+static void QT_FASTCALL convertRGBA64ToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
+{
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
+ for (int i = 0; i < count; ++i) {
+ auto c = in[i];
+ buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+ }
+}
+
+static void QT_FASTCALL convertRGBA16FPMToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
+{
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
+}
+
+static void QT_FASTCALL convertRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
+{
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
+}
+
+static Convert64ToFPFunc convert64ToRGBA32F[] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertRGBA64ToRGBA32F,
+ convertRGBA64PMToRGBA32F,
+ convertRGBA64ToRGBA32F,
+ nullptr,
+ nullptr,
+ convertRGBA16FToRGBA32F,
+ convertRGBA16FPMToRGBA32F,
+ convertRGBA16FToRGBA32F,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+static_assert(std::size(convert64ToRGBA32F) == QImage::NImageFormats);
+
+static void convertRGBA32FToRGBA32FPM(QRgbaFloat32 *buffer, int count)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = buffer[i].premultiplied();
+}
+
+static void convertRGBA32FToRGBA32F(QRgbaFloat32 *, int)
+{
+}
+
#endif
/*
@@ -142,7 +359,7 @@ static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int,
return buffer;
}
-static DestFetchProc destFetchProc[QImage::NImageFormats] =
+static DestFetchProc destFetchProc[] =
{
nullptr, // Format_Invalid
destFetchMono, // Format_Mono,
@@ -174,8 +391,17 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
destFetch, // Format_RGBA64_Premultiplied
destFetch, // Format_Grayscale16
destFetch, // Format_BGR888
+ destFetch, // Format_RGBX16FPx4
+ destFetch, // Format_RGBA16FPx4
+ destFetch, // Format_RGBA16FPx4_Premultiplied
+ destFetch, // Format_RGBX32FPx4
+ destFetch, // Format_RGBA32FPx4
+ destFetch, // Format_RGBA32FPx4_Premultiplied
+ destFetch, // Format_CMYK8888
};
+static_assert(std::size(destFetchProc) == QImage::NImageFormats);
+
#if QT_CONFIG(raster_64bit)
static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
{
@@ -193,7 +419,7 @@ static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer
return buffer;
}
-static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
+static DestFetchProc64 destFetchProc64[] =
{
nullptr, // Format_Invalid
nullptr, // Format_Mono,
@@ -225,7 +451,75 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
destFetchRGB64, // Format_RGBA64_Premultiplied
destFetch64, // Format_Grayscale16
destFetch64, // Format_BGR888
+ destFetch64, // Format_RGBX16FPx4
+ destFetch64, // Format_RGBA16FPx4
+ destFetch64, // Format_RGBA16FPx4_Premultiplied
+ destFetch64, // Format_RGBX32FPx4
+ destFetch64, // Format_RGBA32FPx4
+ destFetch64, // Format_RGBA32FPx4_Premultiplied
+ destFetch64, // Format_CMYK8888
};
+
+static_assert(std::size(destFetchProc64) == QImage::NImageFormats);
+#endif
+
+#if QT_CONFIG(raster_fp)
+static QRgbaFloat32 *QT_FASTCALL destFetchFP(QRgbaFloat32 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
+{
+ return const_cast<QRgbaFloat32 *>(qFetchToRGBA32F[rasterBuffer->format](buffer, rasterBuffer->scanLine(y), x, length, nullptr, nullptr));
+}
+
+static QRgbaFloat32 *QT_FASTCALL destFetchRGBFP(QRgbaFloat32 *, QRasterBuffer *rasterBuffer, int x, int y, int)
+{
+ return reinterpret_cast<QRgbaFloat32 *>(rasterBuffer->scanLine(y)) + x;
+}
+
+static QRgbaFloat32 *QT_FASTCALL destFetchFPUndefined(QRgbaFloat32 *buffer, QRasterBuffer *, int, int, int)
+{
+ return buffer;
+}
+static DestFetchProcFP destFetchProcFP[] =
+{
+ nullptr, // Format_Invalid
+ nullptr, // Format_Mono,
+ nullptr, // Format_MonoLSB
+ nullptr, // Format_Indexed8
+ destFetchFP, // Format_RGB32
+ destFetchFP, // Format_ARGB32,
+ destFetchFP, // Format_ARGB32_Premultiplied
+ destFetchFP, // Format_RGB16
+ destFetchFP, // Format_ARGB8565_Premultiplied
+ destFetchFP, // Format_RGB666
+ destFetchFP, // Format_ARGB6666_Premultiplied
+ destFetchFP, // Format_RGB555
+ destFetchFP, // Format_ARGB8555_Premultiplied
+ destFetchFP, // Format_RGB888
+ destFetchFP, // Format_RGB444
+ destFetchFP, // Format_ARGB4444_Premultiplied
+ destFetchFP, // Format_RGBX8888
+ destFetchFP, // Format_RGBA8888
+ destFetchFP, // Format_RGBA8888_Premultiplied
+ destFetchFP, // Format_BGR30
+ destFetchFP, // Format_A2BGR30_Premultiplied
+ destFetchFP, // Format_RGB30
+ destFetchFP, // Format_A2RGB30_Premultiplied
+ destFetchFP, // Format_Alpha8
+ destFetchFP, // Format_Grayscale8
+ destFetchFP, // Format_RGBX64
+ destFetchFP, // Format_RGBA64
+ destFetchFP, // Format_RGBA64_Premultiplied
+ destFetchFP, // Format_Grayscale16
+ destFetchFP, // Format_BGR888
+ destFetchFP, // Format_RGBX16FPx4
+ destFetchFP, // Format_RGBA16FPx4
+ destFetchFP, // Format_RGBA16FPx4_Premultiplied
+ destFetchRGBFP, // Format_RGBX32FPx4
+ destFetchFP, // Format_RGBA32FPx4
+ destFetchRGBFP, // Format_RGBA32FPx4_Premultiplied
+ destFetchFP, // Format_CMYK8888
+};
+
+static_assert(std::size(destFetchProcFP) == QImage::NImageFormats);
#endif
/*
@@ -234,9 +528,8 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
*/
static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
{
- QRgb color_0 = qPremultiply(rbuf->destColor0);
- QRgb color_1 = qPremultiply(rbuf->destColor1);
- color = qPremultiply(color);
+ const QRgb color_0 = rbuf->destColor0;
+ const QRgb color_1 = rbuf->destColor1;
int r = qRed(color);
int g = qGreen(color);
@@ -334,7 +627,52 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con
store(dest, buffer, x, length, nullptr, nullptr);
}
-static DestStoreProc destStoreProc[QImage::NImageFormats] =
+static void QT_FASTCALL destStoreGray8(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
+{
+ uchar *data = rasterBuffer->scanLine(y) + x;
+
+ bool failed = false;
+ for (int k = 0; k < length; ++k) {
+ if (!qIsGray(buffer[k])) {
+ failed = true;
+ break;
+ }
+ data[k] = qRed(buffer[k]);
+ }
+ if (failed) { // Non-gray colors
+ QColorSpace fromCS = rasterBuffer->colorSpace.isValid() ? rasterBuffer->colorSpace : QColorSpace::SRgb;
+ QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
+ QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
+
+ tfd->applyReturnGray(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ }
+}
+
+static void QT_FASTCALL destStoreGray16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
+{
+ quint16 *data = reinterpret_cast<quint16 *>(rasterBuffer->scanLine(y)) + x;
+
+ bool failed = false;
+ for (int k = 0; k < length; ++k) {
+ if (!qIsGray(buffer[k])) {
+ failed = true;
+ break;
+ }
+ data[k] = qRed(buffer[k]) * 257;
+ }
+ if (failed) { // Non-gray colors
+ QColorSpace fromCS = rasterBuffer->colorSpace.isValid() ? rasterBuffer->colorSpace : QColorSpace::SRgb;
+ QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
+ QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
+
+ QRgba64 tmp_line[BufferSize];
+ for (int k = 0; k < length; ++k)
+ tmp_line[k] = QRgba64::fromArgb32(buffer[k]);
+ tfd->applyReturnGray(data, tmp_line, length, QColorTransformPrivate::InputPremultiplied);
+ }
+}
+
+static DestStoreProc destStoreProc[] =
{
nullptr, // Format_Invalid
destStoreMono, // Format_Mono,
@@ -360,14 +698,23 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] =
destStore, // Format_RGB30
destStore, // Format_A2RGB30_Premultiplied
destStore, // Format_Alpha8
- destStore, // Format_Grayscale8
+ destStoreGray8, // Format_Grayscale8
destStore, // Format_RGBX64
destStore, // Format_RGBA64
destStore, // Format_RGBA64_Premultiplied
- destStore, // Format_Grayscale16
+ destStoreGray16, // Format_Grayscale16
destStore, // Format_BGR888
+ destStore, // Format_RGBX16FPx4
+ destStore, // Format_RGBA16FPx4
+ destStore, // Format_RGBA16FPx4_Premultiplied
+ destStore, // Format_RGBX32FPx4
+ destStore, // Format_RGBA32FPx4
+ destStore, // Format_RGBA32FPx4_Premultiplied
+ destStore, // Format_CMYK8888
};
+static_assert(std::size(destStoreProc) == QImage::NImageFormats);
+
#if QT_CONFIG(raster_64bit)
static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
{
@@ -384,7 +731,51 @@ static void QT_FASTCALL destStore64RGBA64(QRasterBuffer *rasterBuffer, int x, in
}
}
-static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
+static void QT_FASTCALL destStore64Gray8(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
+{
+ uchar *data = rasterBuffer->scanLine(y) + x;
+
+ bool failed = false;
+ for (int k = 0; k < length; ++k) {
+ if (buffer[k].red() != buffer[k].green() || buffer[k].red() != buffer[k].blue()) {
+ failed = true;
+ break;
+ }
+ data[k] = buffer[k].red8();
+ }
+ if (failed) { // Non-gray colors
+ QColorSpace fromCS = rasterBuffer->colorSpace.isValid() ? rasterBuffer->colorSpace : QColorSpace::SRgb;
+ QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
+ QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
+
+ quint16 gray_line[BufferSize];
+ tfd->applyReturnGray(gray_line, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ for (int k = 0; k < length; ++k)
+ data[k] = qt_div_257(gray_line[k]);
+ }
+}
+
+static void QT_FASTCALL destStore64Gray16(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
+{
+ quint16 *data = reinterpret_cast<quint16 *>(rasterBuffer->scanLine(y)) + x;
+
+ bool failed = false;
+ for (int k = 0; k < length; ++k) {
+ if (buffer[k].red() != buffer[k].green() || buffer[k].red() != buffer[k].blue()) {
+ failed = true;
+ break;
+ }
+ data[k] = buffer[k].red();
+ }
+ if (failed) { // Non-gray colors
+ QColorSpace fromCS = rasterBuffer->colorSpace.isValid() ? rasterBuffer->colorSpace : QColorSpace::SRgb;
+ QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
+ QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
+ tfd->applyReturnGray(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ }
+}
+
+static DestStoreProc64 destStoreProc64[] =
{
nullptr, // Format_Invalid
nullptr, // Format_Mono,
@@ -410,13 +801,31 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
destStore64, // Format_RGB30
destStore64, // Format_A2RGB30_Premultiplied
destStore64, // Format_Alpha8
- destStore64, // Format_Grayscale8
+ destStore64Gray8, // Format_Grayscale8
nullptr, // Format_RGBX64
destStore64RGBA64, // Format_RGBA64
nullptr, // Format_RGBA64_Premultiplied
- destStore64, // Format_Grayscale16
+ destStore64Gray16, // Format_Grayscale16
destStore64, // Format_BGR888
+ destStore64, // Format_RGBX16FPx4
+ destStore64, // Format_RGBA16FPx4
+ destStore64, // Format_RGBA16FPx4_Premultiplied
+ destStore64, // Format_RGBX32FPx4
+ destStore64, // Format_RGBA32FPx4
+ destStore64, // Format_RGBA32FPx4_Premultiplied
+ destStore64, // Format_CMYK8888
};
+
+static_assert(std::size(destStoreProc64) == QImage::NImageFormats);
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL destStoreFP(QRasterBuffer *rasterBuffer, int x, int y, const QRgbaFloat32 *buffer, int length)
+{
+ auto store = qStoreFromRGBA32F[rasterBuffer->format];
+ uchar *dest = rasterBuffer->scanLine(y);
+ store(dest, buffer, x, length, nullptr, nullptr);
+}
#endif
/*
@@ -484,6 +893,15 @@ static const QRgba64 *QT_FASTCALL fetchUntransformedRGBA64PM(QRgba64 *, const Op
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgbaFloat32 *QT_FASTCALL fetchUntransformedFP(QRgbaFloat32 *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
+{
+ const auto fetch = qFetchToRGBA32F[data->texture.format];
+ return fetch(buffer, data->texture.scanLine(y), x, length, data->texture.colorTable, nullptr);
+}
+#endif
+
template<TextureBlendType blendType>
inline void fetchTransformed_pixelBounds(int max, int l1, int l2, int &v)
{
@@ -528,9 +946,9 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
constexpr bool useFetch = (bpp < QPixelLayout::BPP32) && sizeof(T) == sizeof(uint);
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
if (!useFetch)
- Q_ASSERT(layout->bpp == bpp);
+ Q_ASSERT(layout->bpp == bpp || (layout->bpp == QPixelLayout::BPP16FPx4 && bpp == QPixelLayout::BPP64));
// When templated 'fetch' should be inlined at compile time:
- const FetchPixelFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout->bpp] : FetchPixelFunc(qFetchPixel<bpp>);
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout->bpp] : Fetch1PixelFunc(fetch1Pixel<bpp>);
if (canUseFastMatrixPath(cx, cy, length, data)) {
// The increment pr x in the scanline
@@ -561,8 +979,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1);
if (x1 == x2)
break;
- if (useFetch)
- buffer[i] = fetch(src, x1);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, x1);
else
buffer[i] = reinterpret_cast<const T*>(src)[x1];
fx += fdx;
@@ -570,8 +988,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < fastLen; ++i) {
int px = (fx >> 16);
- if (useFetch)
- buffer[i] = fetch(src, px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, px);
else
buffer[i] = reinterpret_cast<const T*>(src)[px];
fx += fdx;
@@ -581,8 +999,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < length; ++i) {
int px = (fx >> 16);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
- if (useFetch)
- buffer[i] = fetch(src, px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(src, px);
else
buffer[i] = reinterpret_cast<const T*>(src)[px];
fx += fdx;
@@ -609,8 +1027,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1);
if (x1 == x2 && y1 == y2)
break;
- if (useFetch)
- buffer[i] = fetch(image.scanLine(y1), x1);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(y1), x1);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(y1))[x1];
fx += fdx;
@@ -620,8 +1038,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
for (; i < fastLen; ++i) {
int px = (fx >> 16);
int py = (fy >> 16);
- if (useFetch)
- buffer[i] = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(py), px);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
fx += fdx;
@@ -634,8 +1052,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
int py = (fy >> 16);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
- if (useFetch)
- buffer[i] = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ buffer[i] = fetch1(image.scanLine(py), px);
else
buffer[i] = reinterpret_cast<const T*>(image.scanLine(py))[px];
fx += fdx;
@@ -662,8 +1080,8 @@ static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *dat
fetchTransformed_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, py);
fetchTransformed_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, px);
- if (useFetch)
- *b = fetch(image.scanLine(py), px);
+ if constexpr (useFetch)
+ *b = fetch1(image.scanLine(py), px);
else
*b = reinterpret_cast<const T*>(image.scanLine(py))[px];
@@ -696,7 +1114,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
int y, int x, int length)
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
- if (layout->bpp != QPixelLayout::BPP64) {
+ if (layout->bpp < QPixelLayout::BPP64) {
uint buffer32[BufferSize];
Q_ASSERT(length <= BufferSize);
if (layout->bpp == QPixelLayout::BPP32)
@@ -706,9 +1124,37 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
return layout->convertToRGBA64PM(buffer, buffer32, length, data->texture.colorTable, nullptr);
}
- fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, QRgba64>(buffer, data, y, x, length);
- if (data->texture.format == QImage::Format_RGBA64)
- convertRGBA64ToRGBA64PM(buffer, length);
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, quint64>(reinterpret_cast<quint64*>(buffer), data, y, x, length);
+ if (auto convert = convert64ToRGBA64PM[data->texture.format])
+ convert(buffer, length);
+ return buffer;
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
+static const QRgbaFloat32 *QT_FASTCALL fetchTransformedFP(QRgbaFloat32 *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ if (layout->bpp < QPixelLayout::BPP64) {
+ uint buffer32[BufferSize];
+ Q_ASSERT(length <= BufferSize);
+ if (layout->bpp == QPixelLayout::BPP32)
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP32, uint>(buffer32, data, y, x, length);
+ else
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPPNone, uint>(buffer32, data, y, x, length);
+ qConvertToRGBA32F[data->texture.format](buffer, buffer32, length, data->texture.colorTable, nullptr);
+ } else if (layout->bpp < QPixelLayout::BPP32FPx4) {
+ quint64 buffer64[BufferSize];
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP64, quint64>(buffer64, data, y, x, length);
+ convert64ToRGBA32F[data->texture.format](buffer, buffer64, length);
+ } else {
+ fetchTransformed_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgbaFloat32>(buffer, data, y, x, length);
+ if (data->texture.format == QImage::Format_RGBA32FPx4)
+ convertRGBA32FToRGBA32FPM(buffer, length);
+ return buffer;
+ }
return buffer;
}
#endif
@@ -847,7 +1293,7 @@ static void QT_FASTCALL intermediate_adder(uint *b, uint *end, const Intermediat
{
#if defined(QT_COMPILER_SUPPORTS_AVX2)
extern void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx);
- if (qCpuHasFeature(AVX2))
+ if (qCpuHasFeature(ArchHaswell))
return intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx);
#endif
@@ -1484,7 +1930,7 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
{
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
- Q_CONSTEXPR int tiled = (blendType == BlendTransformedBilinearTiled) ? 1 : 0;
+ constexpr int tiled = (blendType == BlendTransformedBilinearTiled) ? 1 : 0;
uint *end = buffer + length;
uint *b = buffer;
@@ -1583,7 +2029,7 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_scale_helper(uint *b, ui
int &fx, int &fy, int fdx, int /*fdy*/)
{
const QPixelLayout *layout = &qPixelLayouts[image.format];
- const QVector<QRgb> *clut = image.colorTable;
+ const QList<QRgb> *clut = image.colorTable;
const FetchAndConvertPixelsFunc fetch = layout->fetchToARGB32PM;
int y1 = (fy >> 16);
@@ -1681,8 +2127,8 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
if (useFetch)
Q_ASSERT(sizeof(T) == sizeof(uint));
else
- Q_ASSERT(layout.bpp == bpp);
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>;
+ Q_ASSERT(layout.bpp == bpp || (layout.bpp == QPixelLayout::BPP16FPx4 && bpp == QPixelLayout::BPP64));
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout.bpp] : fetch1Pixel<bpp>;
if (fdy == 0) {
int y1 = (fy >> 16);
int y2;
@@ -1698,7 +2144,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
if (x1 != x2)
break;
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = buf1[i * 2 + 1] = fetch1(s1, x1);
buf2[i * 2 + 0] = buf2[i * 2 + 1] = fetch1(s2, x1);
} else {
@@ -1715,7 +2161,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
for (; i < fastLen; ++i) {
int x = (fx >> 16);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x);
buf1[i * 2 + 1] = fetch1(s1, x + 1);
buf2[i * 2 + 0] = fetch1(s2, x);
@@ -1734,7 +2180,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
int x1 = (fx >> 16);
int x2;
fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1761,7 +2207,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
break;
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1790,7 +2236,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
int y = (fy >> 16);
const uchar *s1 = image.scanLine(y);
const uchar *s2 = s1 + image.bytesPerLine;
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x);
buf1[i * 2 + 1] = fetch1(s1, x + 1);
buf2[i * 2 + 0] = fetch1(s2, x);
@@ -1816,7 +2262,7 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1846,7 +2292,7 @@ static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2,
else
Q_ASSERT(layout.bpp == bpp);
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixelTable[layout.bpp] : qFetchPixel<bpp>;
+ const Fetch1PixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? fetch1PixelTable[layout.bpp] : fetch1Pixel<bpp>;
for (int i = 0; i < len; ++i) {
const qreal iw = fw == 0 ? 16384 : 1 / fw;
@@ -1866,7 +2312,7 @@ static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2,
const uchar *s1 = image.scanLine(y1);
const uchar *s2 = image.scanLine(y2);
- if (useFetch) {
+ if constexpr (useFetch) {
buf1[i * 2 + 0] = fetch1(s1, x1);
buf1[i * 2 + 1] = fetch1(s1, x2);
buf2[i * 2 + 0] = fetch1(s2, x1);
@@ -1890,7 +2336,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
const QSpanData *data, int y, int x, int length)
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
- const QVector<QRgb> *clut = data->texture.colorTable;
+ const QList<QRgb> *clut = data->texture.colorTable;
Q_ASSERT(bpp == QPixelLayout::BPPNone || layout->bpp == bpp);
const qreal cx = x + qreal(0.5);
@@ -2038,7 +2484,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
int y, int x, int length)
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
- const QVector<QRgb> *clut = data->texture.colorTable;
+ const auto *clut = data->texture.colorTable;
+ const auto convert = layout->convertToRGBA64PM;
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
@@ -2047,7 +2494,6 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
uint sbuf2[BufferSize];
alignas(8) QRgba64 buf1[BufferSize];
alignas(8) QRgba64 buf2[BufferSize];
- QRgba64 *end = buffer + length;
QRgba64 *b = buffer;
if (canUseFastMatrixPath(cx, cy, length, data)) {
@@ -2068,20 +2514,20 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
if (fdy == 0) { //simple scale, no rotation
while (length) {
- int len = qMin(length, BufferSize / 2);
- int disty = (fy & 0x0000ffff);
+ const int len = qMin(length, BufferSize / 2);
+ const int disty = (fy & 0x0000ffff);
#if defined(__SSE2__)
const __m128i vdy = _mm_set1_epi16(disty);
const __m128i vidy = _mm_set1_epi16(0x10000 - disty);
#endif
fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
if (disty)
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
- int distx = (fx & 0x0000ffff);
+ const int distx = (fx & 0x0000ffff);
#if defined(__SSE2__)
__m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2));
if (disty) {
@@ -2106,17 +2552,17 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
b += len;
}
} else { // rotation or shear
- while (b < end) {
- int len = qMin(length, BufferSize / 2);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
- int distx = (fx & 0x0000ffff);
- int disty = (fy & 0x0000ffff);
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
fx += fdx;
fy += fdy;
@@ -2147,8 +2593,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
const int len = qMin(length, BufferSize / 2);
fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
- layout->convertToRGBA64PM(buf1, sbuf1, len * 2, clut, nullptr);
- layout->convertToRGBA64PM(buf2, sbuf2, len * 2, clut, nullptr);
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
for (int i = 0; i < len; ++i) {
const int distx = distxs[i];
@@ -2167,8 +2613,7 @@ template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buffer, const QSpanData *data,
int y, int x, int length)
{
- Q_ASSERT(qPixelLayouts[data->texture.format].bpp == QPixelLayout::BPP64);
- const auto convert = (data->texture.format == QImage::Format_RGBA64) ? convertRGBA64ToRGBA64PM : convertRGBA64PMToRGBA64PM;
+ const auto convert = convert64ToRGBA64PM[data->texture.format];
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
@@ -2285,17 +2730,368 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf
}
template<TextureBlendType blendType>
+static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_f32x4(QRgba64 *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const auto *clut = data->texture.colorTable;
+ const auto convert = layout->fetchToRGBA64PM;
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ QRgbaFloat32 sbuf1[BufferSize];
+ QRgbaFloat32 sbuf2[BufferSize];
+ alignas(8) QRgba64 buf1[BufferSize];
+ alignas(8) QRgba64 buf2[BufferSize];
+ QRgba64 *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgbaFloat32>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, (const uchar *)sbuf1, 0, len * 2, clut, nullptr);
+ if (!skipsecond)
+ convert(buf2, (const uchar *)sbuf2, 0, len * 2, clut, nullptr);
+
+ for (int i = 0; i < len; ++i) {
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
+ b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
+ fx += fdx;
+ fy += fdy;
+ }
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgbaFloat32>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, (const uchar *)sbuf1, 0, len * 2, clut, nullptr);
+ convert(buf2, (const uchar *)sbuf2, 0, len * 2, clut, nullptr);
+
+ for (int i = 0; i < len; ++i) {
+ const int distx = distxs[i];
+ const int disty = distys[i];
+ b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
+ }
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *,
const QSpanData *data, int y, int x, int length)
{
- if (qPixelLayouts[data->texture.format].bpp == QPixelLayout::BPP64)
+ switch (qPixelLayouts[data->texture.format].bpp) {
+ case QPixelLayout::BPP64:
+ case QPixelLayout::BPP16FPx4:
return fetchTransformedBilinear64_uint64<blendType>(buffer, data, y, x, length);
- return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length);
+ case QPixelLayout::BPP32FPx4:
+ return fetchTransformedBilinear64_f32x4<blendType>(buffer, data, y, x, length);
+ default:
+ return fetchTransformedBilinear64_uint32<blendType>(buffer, data, y, x, length);
+ }
}
#endif
+#if QT_CONFIG(raster_fp)
+static void interpolate_simple_rgba32f(QRgbaFloat32 *b, const QRgbaFloat32 *buf1, const QRgbaFloat32 *buf2, int len,
+ int &fx, int fdx,
+ int &fy, int fdy)
+{
+ for (int i = 0; i < len; ++i) {
+ const int distx = (fx & 0x0000ffff);
+ const int disty = (fy & 0x0000ffff);
+ b[i] = interpolate_4_pixels_rgba32f(buf1 + i*2, buf2 + i*2, distx, disty);
+ fx += fdx;
+ fy += fdy;
+ }
+}
+
+static void interpolate_perspective_rgba32f(QRgbaFloat32 *b, const QRgbaFloat32 *buf1, const QRgbaFloat32 *buf2, int len,
+ unsigned short *distxs,
+ unsigned short *distys)
+{
+ for (int i = 0; i < len; ++i) {
+ const int dx = distxs[i];
+ const int dy = distys[i];
+ b[i] = interpolate_4_pixels_rgba32f(buf1 + i*2, buf2 + i*2, dx, dy);
+ }
+}
+
+template<TextureBlendType blendType>
+static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP_uint32(QRgbaFloat32 *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const auto *clut = data->texture.colorTable;
+ const auto convert = qConvertToRGBA32F[data->texture.format];
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ uint sbuf1[BufferSize];
+ uint sbuf2[BufferSize];
+ QRgbaFloat32 buf1[BufferSize];
+ QRgbaFloat32 buf2[BufferSize];
+ QRgbaFloat32 *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ const auto fetcher =
+ (layout->bpp == QPixelLayout::BPP32)
+ ? fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32, uint>
+ : fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPPNone, uint>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ if (!skipsecond)
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher =
+ (layout->bpp == QPixelLayout::BPP32)
+ ? fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32, uint>
+ : fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPPNone, uint>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, sbuf1, len * 2, clut, nullptr);
+ convert(buf2, sbuf2, len * 2, clut, nullptr);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP_uint64(QRgbaFloat32 *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const auto convert = convert64ToRGBA32F[data->texture.format];
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ quint64 sbuf1[BufferSize];
+ quint64 sbuf2[BufferSize];
+ QRgbaFloat32 buf1[BufferSize];
+ QRgbaFloat32 buf2[BufferSize];
+ QRgbaFloat32 *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP64, quint64>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, sbuf1, len * 2);
+ if (!skipsecond)
+ convert(buf2, sbuf2, len * 2);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP64, quint64>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(sbuf1, sbuf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, sbuf1, len * 2);
+ convert(buf2, sbuf2, len * 2);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP(QRgbaFloat32 *buffer, const QSpanData *data,
+ int y, int x, int length)
+{
+ const auto convert = data->rasterBuffer->format == QImage::Format_RGBA32FPx4 ? convertRGBA32FToRGBA32FPM
+ : convertRGBA32FToRGBA32F;
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ QRgbaFloat32 buf1[BufferSize];
+ QRgbaFloat32 buf2[BufferSize];
+ QRgbaFloat32 *b = buffer;
+
+ if (canUseFastMatrixPath(cx, cy, length, data)) {
+ // The increment pr x in the scanline
+ const int fdx = (int)(data->m11 * fixed_scale);
+ const int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+ const auto fetcher = fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgbaFloat32>;
+
+ const bool skipsecond = (fdy == 0) && ((fy & 0x0000ffff) == 0);
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
+
+ convert(buf1, len * 2);
+ if (!skipsecond)
+ convert(buf2, len * 2);
+
+ interpolate_simple_rgba32f(b, buf1, buf2, len, fx, fdx, fy, fdy);
+
+ length -= len;
+ b += len;
+ }
+ } else { // !(data->fast_matrix)
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP32FPx4, QRgbaFloat32>;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
+
+ while (length) {
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(buf1, buf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
+
+ convert(buf1, len * 2);
+ convert(buf2, len * 2);
+
+ interpolate_perspective_rgba32f(b, buf1, buf2, len, distxs, distys);
+
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
+
+template<TextureBlendType blendType>
+static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP(QRgbaFloat32 *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
+{
+ switch (qPixelLayouts[data->texture.format].bpp) {
+ case QPixelLayout::BPP64:
+ case QPixelLayout::BPP16FPx4:
+ return fetchTransformedBilinearFP_uint64<blendType>(buffer, data, y, x, length);
+ case QPixelLayout::BPP32FPx4:
+ return fetchTransformedBilinearFP<blendType>(buffer, data, y, x, length);
+ default:
+ return fetchTransformedBilinearFP_uint32<blendType>(buffer, data, y, x, length);
+ }
+}
+#endif // QT_CONFIG(raster_fp)
+
// FetchUntransformed can have more specialized methods added depending on SIMD features.
-static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
+static SourceFetchProc sourceFetchUntransformed[] = {
nullptr, // Invalid
fetchUntransformed, // Mono
fetchUntransformed, // MonoLsb
@@ -2326,9 +3122,18 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
fetchUntransformed, // RGBA64_Premultiplied
fetchUntransformed, // Grayscale16
fetchUntransformed, // BGR888
+ fetchUntransformed, // RGBX16FPx4
+ fetchUntransformed, // RGBA16FPx4
+ fetchUntransformed, // RGBA16FPx4_Premultiplied
+ fetchUntransformed, // RGBX32Px4
+ fetchUntransformed, // RGBA32FPx4
+ fetchUntransformed, // RGBA32FPx4_Premultiplied
+ fetchUntransformed, // CMYK8888
};
-static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
+static_assert(std::size(sourceFetchUntransformed) == QImage::NImageFormats);
+
+static const SourceFetchProc sourceFetchGeneric[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPPNone>, // Transformed
@@ -2337,7 +3142,9 @@ static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPPNone> // TransformedBilinearTiled
};
-static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
+static_assert(std::size(sourceFetchGeneric) == NBlendTypes);
+
+static SourceFetchProc sourceFetchARGB32PM[] = {
fetchUntransformedARGB32PM, // Untransformed
fetchUntransformedARGB32PM, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed
@@ -2346,7 +3153,9 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled
};
-static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
+static_assert(std::size(sourceFetchARGB32PM) == NBlendTypes);
+
+static SourceFetchProc sourceFetchAny16[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed
@@ -2355,7 +3164,9 @@ static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled
};
-static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
+static_assert(std::size(sourceFetchAny16) == NBlendTypes);
+
+static SourceFetchProc sourceFetchAny32[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed
@@ -2364,6 +3175,8 @@ static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32> // TransformedBilinearTiled
};
+static_assert(std::size(sourceFetchAny32) == NBlendTypes);
+
static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format)
{
if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied)
@@ -2378,7 +3191,7 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage:
}
#if QT_CONFIG(raster_64bit)
-static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = {
+static const SourceFetchProc64 sourceFetchGeneric64[] = {
fetchUntransformed64, // Untransformed
fetchUntransformed64, // Tiled
fetchTransformed64<BlendTransformed>, // Transformed
@@ -2387,7 +3200,9 @@ static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = {
fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
};
-static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = {
+static_assert(std::size(sourceFetchGeneric64) == NBlendTypes);
+
+static const SourceFetchProc64 sourceFetchRGBA64PM[] = {
fetchUntransformedRGBA64PM, // Untransformed
fetchUntransformedRGBA64PM, // Tiled
fetchTransformed64<BlendTransformed>, // Transformed
@@ -2396,6 +3211,8 @@ static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = {
fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
};
+static_assert(std::size(sourceFetchRGBA64PM) == NBlendTypes);
+
static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format)
{
if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied)
@@ -2404,9 +3221,27 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm
}
#endif
+#if QT_CONFIG(raster_fp)
+static const SourceFetchProcFP sourceFetchGenericFP[] = {
+ fetchUntransformedFP, // Untransformed
+ fetchUntransformedFP, // Tiled
+ fetchTransformedFP<BlendTransformed>, // Transformed
+ fetchTransformedFP<BlendTransformedTiled>, // TransformedTiled
+ fetchTransformedBilinearFP<BlendTransformedBilinear>, // Bilinear
+ fetchTransformedBilinearFP<BlendTransformedBilinearTiled> // BilinearTiled
+};
+
+static_assert(std::size(sourceFetchGenericFP) == NBlendTypes);
+
+static inline SourceFetchProcFP getSourceFetchFP(TextureBlendType blendType, QImage::Format /*format*/)
+{
+ return sourceFetchGenericFP[blendType];
+}
+#endif
#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)
{
@@ -2422,6 +3257,22 @@ static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int f
}
#endif
+#if QT_CONFIG(raster_fp)
+static inline QRgbaFloat32 qt_gradient_pixelFP(const QGradientData *data, qreal pos)
+{
+ int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
+ QRgba64 rgb64 = data->colorTable64[qt_gradient_clamp(data, ipos)];
+ return QRgbaFloat32::fromRgba64(rgb64.red(),rgb64.green(), rgb64.blue(), rgb64.alpha());
+}
+
+static inline QRgbaFloat32 qt_gradient_pixelFP_fixed(const QGradientData *data, int fixed_pos)
+{
+ int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
+ QRgba64 rgb64 = data->colorTable64[qt_gradient_clamp(data, ipos)];
+ return QRgbaFloat32::fromRgba64(rgb64.red(), rgb64.green(), rgb64.blue(), rgb64.alpha());
+}
+#endif
+
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
{
v->dx = data->gradient.linear.end.x - data->gradient.linear.origin.x;
@@ -2442,6 +3293,7 @@ public:
static Type null() { return 0; }
static Type fetchSingle(const QGradientData& gradient, qreal v)
{
+ Q_ASSERT(std::isfinite(v));
return qt_gradient_pixel(&gradient, v);
}
static Type fetchSingle(const QGradientData& gradient, int v)
@@ -2462,6 +3314,7 @@ public:
static Type null() { return QRgba64::fromRgba64(0); }
static Type fetchSingle(const QGradientData& gradient, qreal v)
{
+ Q_ASSERT(std::isfinite(v));
return qt_gradient_pixel64(&gradient, v);
}
static Type fetchSingle(const QGradientData& gradient, int v)
@@ -2475,6 +3328,30 @@ public:
};
#endif
+#if QT_CONFIG(raster_fp)
+class GradientBaseFP
+{
+public:
+ typedef QRgbaFloat32 Type;
+ static Type null() { return QRgbaFloat32::fromRgba64(0,0,0,0); }
+ static Type fetchSingle(const QGradientData& gradient, qreal v)
+ {
+ Q_ASSERT(std::isfinite(v));
+ return qt_gradient_pixelFP(&gradient, v);
+ }
+ static Type fetchSingle(const QGradientData& gradient, int v)
+ {
+ return qt_gradient_pixelFP_fixed(&gradient, v);
+ }
+ static void memfill(Type *buffer, Type fill, int length)
+ {
+ quint64 fillCopy;
+ memcpy(&fillCopy, &fill, sizeof(quint64));
+ qt_memfill64((quint64*)buffer, fillCopy, length);
+ }
+};
+#endif
+
template<class GradientBase, typename BlendType>
static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(
BlendType *buffer, const Operator *op, const QSpanData *data,
@@ -2503,10 +3380,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);
@@ -2558,6 +3437,13 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe
return qt_fetch_linear_gradient_template<GradientBase64, QRgba64>(buffer, op, data, y, x, length);
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgbaFloat32 * QT_FASTCALL qt_fetch_linear_gradient_rgbfp(QRgbaFloat32 *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_linear_gradient_template<GradientBaseFP, QRgbaFloat32>(buffer, op, data, y, x, length);
+}
+#endif
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
{
@@ -2568,7 +3454,6 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q
v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
- v->inv2a = 1 / (2 * v->a);
v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
}
@@ -2601,7 +3486,13 @@ public:
}
} else {
while (buffer < end) {
- *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b);
+ BlendType result = GradientBase::null();
+ if (det >= 0) {
+ qreal w = qSqrt(det) - b;
+ result = GradientBase::fetchSingle(data->gradient, w);
+ }
+
+ *buffer++ = result;
det += delta_det;
delta_det += delta_delta_det;
@@ -2627,6 +3518,14 @@ const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, cons
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgbaFloat32 * QT_FASTCALL qt_fetch_radial_gradient_rgbfp(QRgbaFloat32 *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<RadialFetchPlain<GradientBaseFP>, QRgbaFloat32>(buffer, op, data, y, x, length);
+}
+#endif
+
template <class GradientBase, typename BlendType>
static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template(
BlendType *buffer, const QSpanData *data,
@@ -2692,26 +3591,44 @@ static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buff
}
#endif
+#if QT_CONFIG(raster_fp)
+static const QRgbaFloat32 * QT_FASTCALL qt_fetch_conical_gradient_rgbfp(QRgbaFloat32 *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_conical_gradient_template<GradientBaseFP, QRgbaFloat32>(buffer, data, y, x, length);
+}
+#endif
+
extern CompositionFunctionSolid qt_functionForModeSolid_C[];
extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[];
+extern CompositionFunctionSolidFP qt_functionForModeSolidFP_C[];
static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C;
#if QT_CONFIG(raster_64bit)
static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C;
#endif
+#if QT_CONFIG(raster_fp)
+static const CompositionFunctionSolidFP *functionForModeSolidFP = qt_functionForModeSolidFP_C;
+#endif
extern CompositionFunction qt_functionForMode_C[];
extern CompositionFunction64 qt_functionForMode64_C[];
+extern CompositionFunctionFP qt_functionForModeFP_C[];
static const CompositionFunction *functionForMode = qt_functionForMode_C;
#if QT_CONFIG(raster_64bit)
static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C;
#endif
+#if QT_CONFIG(raster_fp)
+static const CompositionFunctionFP *functionForModeFP = qt_functionForModeFP_C;
+#endif
static TextureBlendType getBlendType(const QSpanData *data)
{
TextureBlendType ft;
- if (data->txop <= QTransform::TxTranslate)
+ if (data->texture.type == QTextureData::Pattern)
+ ft = BlendTiled;
+ else if (data->txop <= QTransform::TxTranslate)
if (data->texture.type == QTextureData::Tiled)
ft = BlendTiled;
else
@@ -2729,18 +3646,16 @@ static TextureBlendType getBlendType(const QSpanData *data)
return ft;
}
-static inline Operator getOperator(const QSpanData *data, const QSpan *spans, int spanCount)
+static inline Operator getOperator(const QSpanData *data, const QT_FT_Span *spans, int spanCount)
{
Operator op;
bool solidSource = false;
-
switch(data->type) {
case QSpanData::Solid:
- solidSource = data->solidColor.isOpaque();
+ solidSource = data->solidColor.alphaF() >= 1.0f;
op.srcFetch = nullptr;
-#if QT_CONFIG(raster_64bit)
op.srcFetch64 = nullptr;
-#endif
+ op.srcFetchFP = nullptr;
break;
case QSpanData::LinearGradient:
solidSource = !data->gradient.alphaColor;
@@ -2749,6 +3664,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_linear_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_linear_gradient_rgbfp;
+#endif
break;
case QSpanData::RadialGradient:
solidSource = !data->gradient.alphaColor;
@@ -2757,6 +3675,9 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_radial_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_radial_gradient_rgbfp;
+#endif
break;
case QSpanData::ConicalGradient:
solidSource = !data->gradient.alphaColor;
@@ -2764,12 +3685,18 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.srcFetch64 = qt_fetch_conical_gradient_rgb64;
#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = qt_fetch_conical_gradient_rgbfp;
+#endif
break;
case QSpanData::Texture:
solidSource = !data->texture.hasAlpha;
op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format);
#if QT_CONFIG(raster_64bit)
- op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);;
+ op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);
+#endif
+#if QT_CONFIG(raster_fp)
+ op.srcFetchFP = getSourceFetchFP(getBlendType(data), data->texture.format);
#endif
break;
default:
@@ -2777,7 +3704,10 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
break;
}
#if !QT_CONFIG(raster_64bit)
- op.srcFetch64 = 0;
+ op.srcFetch64 = nullptr;
+#endif
+#if !QT_CONFIG(raster_fp)
+ op.srcFetchFP = nullptr;
#endif
op.mode = data->rasterBuffer->compositionMode;
@@ -2788,11 +3718,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
#if QT_CONFIG(raster_64bit)
op.destFetch64 = destFetchProc64[data->rasterBuffer->format];
#else
- op.destFetch64 = 0;
+ op.destFetch64 = nullptr;
+#endif
+#if QT_CONFIG(raster_fp)
+ op.destFetchFP = destFetchProcFP[data->rasterBuffer->format];
+#else
+ op.destFetchFP = nullptr;
#endif
if (op.mode == QPainter::CompositionMode_Source &&
(data->type != QSpanData::Texture || data->texture.const_alpha == 256)) {
- const QSpan *lastSpan = spans + spanCount;
+ const QT_FT_Span *lastSpan = spans + spanCount;
bool alphaSpans = false;
while (spans < lastSpan) {
if (spans->coverage != 255) {
@@ -2810,6 +3745,10 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
if (op.destFetch64 != destFetchRGB64)
op.destFetch64 = destFetch64Undefined;
#endif
+#if QT_CONFIG(raster_fp)
+ if (op.destFetchFP != destFetchRGBFP)
+ op.destFetchFP = destFetchFPUndefined;
+#endif
}
}
@@ -2821,9 +3760,18 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
op.funcSolid64 = functionForModeSolid64[op.mode];
op.func64 = functionForMode64[op.mode];
#else
- op.destStore64 = 0;
- op.funcSolid64 = 0;
- op.func64 = 0;
+ op.destStore64 = nullptr;
+ op.funcSolid64 = nullptr;
+ op.func64 = nullptr;
+#endif
+#if QT_CONFIG(raster_fp)
+ op.destStoreFP = destStoreFP;
+ op.funcSolidFP = functionForModeSolidFP[op.mode];
+ op.funcFP = functionForModeFP[op.mode];
+#else
+ op.destStoreFP = nullptr;
+ op.funcSolidFP = nullptr;
+ op.funcFP = nullptr;
#endif
return op;
@@ -2832,6 +3780,12 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP bpp, int x, int y, int length)
{
switch (bpp) {
+ case QPixelLayout::BPP32FPx4: {
+ QRgbaFloat32 *dest = reinterpret_cast<QRgbaFloat32 *>(rasterBuffer->scanLine(y)) + x;
+ qt_memfill_template(dest + 1, dest[0], length - 1);
+ break;
+ }
+ case QPixelLayout::BPP16FPx4:
case QPixelLayout::BPP64: {
quint64 *dest = reinterpret_cast<quint64 *>(rasterBuffer->scanLine(y)) + x;
qt_memfill_template(dest + 1, dest[0], length - 1);
@@ -2865,44 +3819,69 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
// -------------------- blend methods ---------------------
-static void blend_color_generic(int count, const QSpan *spans, void *userData)
+#if defined(QT_USE_THREAD_PARALLEL_FILLS)
+#define QT_THREAD_PARALLEL_FILLS(function) \
+ const int segments = (count + 32) / 64; \
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \
+ if (segments > 1 && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \
+ && threadPool && !threadPool->contains(QThread::currentThread())) { \
+ QSemaphore semaphore; \
+ int c = 0; \
+ for (int i = 0; i < segments; ++i) { \
+ int cn = (count - c) / (segments - i); \
+ threadPool->start([&, c, cn]() { \
+ function(c, c + cn); \
+ semaphore.release(1); \
+ }, 1); \
+ c += cn; \
+ } \
+ semaphore.acquire(segments); \
+ } else \
+ function(0, count)
+#else
+#define QT_THREAD_PARALLEL_FILLS(function) function(0, count)
+#endif
+
+static void blend_color_generic(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[BufferSize];
- Operator op = getOperator(data, nullptr, 0);
- const uint color = data->solidColor.toArgb32();
+ const Operator op = getOperator(data, nullptr, 0);
+ const uint color = data->solidColor.rgba();
const bool solidFill = op.mode == QPainter::CompositionMode_Source;
const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
- while (count--) {
- int x = spans->x;
- int length = spans->len;
- if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length) {
- // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
- op.destStore(data->rasterBuffer, x, spans->y, &color, 1);
- spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length);
- length = 0;
- }
+ auto function = [=] (int cStart, int cEnd) {
+ alignas(16) uint buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStore) {
+ // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
+ op.destStore(data->rasterBuffer, x, spans[c].y, &color, 1);
+ spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
+ length = 0;
+ }
- while (length) {
- int l = qMin(BufferSize, length);
- uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
- op.funcSolid(dest, l, color, spans->coverage);
- if (op.destStore)
- op.destStore(data->rasterBuffer, x, spans->y, dest, l);
- length -= l;
- x += l;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.funcSolid(dest, l, color, spans[c].coverage);
+ if (op.destStore)
+ op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
+ length -= l;
+ x += l;
+ }
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
-static void blend_color_argb(int count, const QSpan *spans, void *userData)
+static void blend_color_argb(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
const Operator op = getOperator(data, nullptr, 0);
- const uint color = data->solidColor.toArgb32();
+ const uint color = data->solidColor.rgba();
if (op.mode == QPainter::CompositionMode_Source) {
// inline for performance
@@ -2924,218 +3903,186 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
}
return;
}
-
- while (count--) {
- uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
- op.funcSolid(target, spans->len, color, spans->coverage);
- ++spans;
- }
+ const auto funcSolid = op.funcSolid;
+ auto function = [=] (int cStart, int cEnd) {
+ for (int c = cStart; c < cEnd; ++c) {
+ uint *target = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + spans[c].x;
+ funcSolid(target, spans[c].len, color, spans[c].coverage);
+ }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
-void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
+static void blend_color_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
{
#if QT_CONFIG(raster_64bit)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- Operator op = getOperator(data, nullptr, 0);
+ const Operator op = getOperator(data, nullptr, 0);
if (!op.funcSolid64) {
qCDebug(lcQtGuiDrawHelper, "blend_color_generic_rgb64: unsupported 64bit blend attempted, falling back to 32-bit");
return blend_color_generic(count, spans, userData);
}
- alignas(8) QRgba64 buffer[BufferSize];
- const QRgba64 color = data->solidColor;
+ const QRgba64 color = data->solidColor.rgba64();
const bool solidFill = op.mode == QPainter::CompositionMode_Source;
const QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
- while (count--) {
- int x = spans->x;
- int length = spans->len;
- if (solidFill && bpp >= QPixelLayout::BPP8 && spans->coverage == 255 && length && op.destStore64) {
- // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
- op.destStore64(data->rasterBuffer, x, spans->y, &color, 1);
- spanfill_from_first(data->rasterBuffer, bpp, x, spans->y, length);
- length = 0;
- }
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ alignas(16) QRgba64 buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStore64) {
+ // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
+ op.destStore64(data->rasterBuffer, x, spans[c].y, &color, 1);
+ spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
+ length = 0;
+ }
- while (length) {
- int l = qMin(BufferSize, length);
- QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
- op.funcSolid64(dest, l, color, spans->coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
- length -= l;
- x += l;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.funcSolid64(dest, l, color, spans[c].coverage);
+ if (op.destStore64)
+ op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
+ length -= l;
+ x += l;
+ }
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
#else
blend_color_generic(count, spans, userData);
#endif
}
-static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
+static void blend_color_generic_fp(int count, const QT_FT_Span *spans, void *userData)
{
+#if QT_CONFIG(raster_fp)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+ const Operator op = getOperator(data, nullptr, 0);
+ if (!op.funcSolidFP || !op.destFetchFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_color_generic_fp: unsupported 4xF16 blend attempted, falling back to 32-bit");
+ return blend_color_generic(count, spans, userData);
+ }
- /*
- We duplicate a little logic from getOperator() and calculate the
- composition mode directly. This allows blend_color_rgb16 to be used
- from qt_gradient_quint16 with minimal overhead.
- */
- QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
- if (mode == QPainter::CompositionMode_SourceOver && data->solidColor.isOpaque())
- mode = QPainter::CompositionMode_Source;
+ float r, g, b, a;
+ data->solidColor.getRgbF(&r, &g, &b, &a);
+ const QRgbaFloat32 color{r, g, b, a};
+ const bool solidFill = op.mode == QPainter::CompositionMode_Source;
+ QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
- if (mode == QPainter::CompositionMode_Source) {
- // inline for performance
- ushort c = data->solidColor.toRgb16();
- for (; count--; spans++) {
- if (!spans->len)
- continue;
- ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
- if (spans->coverage == 255) {
- qt_memfill(target, c, spans->len);
- } else {
- ushort color = BYTE_MUL_RGB16(c, spans->coverage);
- int ialpha = 255 - spans->coverage;
- const ushort *end = target + spans->len;
- while (target < end) {
- *target = color + BYTE_MUL_RGB16(*target, ialpha);
- ++target;
- }
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ alignas(16) QRgbaFloat32 buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ if (solidFill && bpp >= QPixelLayout::BPP8 && spans[c].coverage == 255 && length && op.destStoreFP) {
+ // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
+ op.destStoreFP(data->rasterBuffer, x, spans[c].y, &color, 1);
+ spanfill_from_first(data->rasterBuffer, bpp, x, spans[c].y, length);
+ length = 0;
}
- }
- return;
- }
- if (mode == QPainter::CompositionMode_SourceOver) {
- for (; count--; spans++) {
- if (!spans->len)
- continue;
- uint color = BYTE_MUL(data->solidColor.toArgb32(), spans->coverage);
- int ialpha = qAlpha(~color);
- ushort c = qConvertRgb32To16(color);
- ushort *target = ((ushort *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
- int len = spans->len;
- bool pre = (((quintptr)target) & 0x3) != 0;
- bool post = false;
- if (pre) {
- // skip to word boundary
- *target = c + BYTE_MUL_RGB16(*target, ialpha);
- ++target;
- --len;
- }
- if (len & 0x1) {
- post = true;
- --len;
- }
- uint *target32 = (uint*)target;
- uint c32 = c | (c<<16);
- len >>= 1;
- uint salpha = (ialpha+1) >> 3; // calculate here rather than in loop
- while (len--) {
- // blend full words
- *target32 = c32 + BYTE_MUL_RGB16_32(*target32, salpha);
- ++target32;
- target += 2;
- }
- if (post) {
- // one last pixel beyond a full word
- *target = c + BYTE_MUL_RGB16(*target, ialpha);
+ while (length) {
+ int l = qMin(BufferSize, length);
+ QRgbaFloat32 *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.funcSolidFP(dest, l, color, spans[c].coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
+ length -= l;
+ x += l;
}
}
- return;
- }
-
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
+#else
blend_color_generic(count, spans, userData);
+#endif
}
template <typename T>
-void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handler)
+void handleSpans(int count, const QT_FT_Span *spans, const QSpanData *data, const Operator &op)
{
- uint const_alpha = 256;
- if (data->type == QSpanData::Texture)
- const_alpha = data->texture.const_alpha;
+ const int const_alpha = (data->type == QSpanData::Texture) ? data->texture.const_alpha : 256;
+ const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256;
- int coverage = 0;
- while (count) {
- if (!spans->len) {
- ++spans;
- --count;
- continue;
- }
- int x = spans->x;
- const int y = spans->y;
- int right = x + spans->len;
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ T handler(data, op);
+ int coverage = 0;
+ for (int c = cStart; c < cEnd;) {
+ if (!spans[c].len) {
+ ++c;
+ continue;
+ }
+ int x = spans[c].x;
+ const int y = spans[c].y;
+ int right = x + spans[c].len;
+ const bool fetchDest = !solidSource || spans[c].coverage < 255;
- // compute length of adjacent spans
- for (int i = 1; i < count && spans[i].y == y && spans[i].x == right; ++i)
- right += spans[i].len;
- int length = right - x;
+ // compute length of adjacent spans
+ for (int i = c + 1; i < cEnd && spans[i].y == y && spans[i].x == right && fetchDest == (!solidSource || spans[i].coverage < 255); ++i)
+ right += spans[i].len;
+ int length = right - x;
- while (length) {
- int l = qMin(BufferSize, length);
- length -= l;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ length -= l;
- int process_length = l;
- int process_x = x;
+ int process_length = l;
+ int process_x = x;
- const typename T::BlendType *src = handler.fetch(process_x, y, process_length);
- int offset = 0;
- while (l > 0) {
- if (x == spans->x) // new span?
- coverage = (spans->coverage * const_alpha) >> 8;
+ const auto *src = handler.fetch(process_x, y, process_length, fetchDest);
+ int offset = 0;
+ while (l > 0) {
+ if (x == spans[c].x) // new span?
+ coverage = (spans[c].coverage * const_alpha) >> 8;
- int right = spans->x + spans->len;
- int len = qMin(l, right - x);
+ int right = spans[c].x + spans[c].len;
+ int len = qMin(l, right - x);
- handler.process(x, y, len, coverage, src, offset);
+ handler.process(x, y, len, coverage, src, offset);
- l -= len;
- x += len;
- offset += len;
+ l -= len;
+ x += len;
+ offset += len;
- if (x == right) { // done with current span?
- ++spans;
- --count;
+ if (x == right) // done with current span?
+ ++c;
}
+ handler.store(process_x, y, process_length);
}
- handler.store(process_x, y, process_length);
}
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
-template<typename T>
struct QBlendBase
{
- typedef T BlendType;
- QBlendBase(QSpanData *d, const Operator &o)
- : data(d)
- , op(o)
- , dest(nullptr)
- {
- }
-
- QSpanData *data;
- Operator op;
-
- BlendType *dest;
-
- alignas(8) BlendType buffer[BufferSize];
- alignas(8) BlendType src_buffer[BufferSize];
+ const QSpanData *data;
+ const Operator &op;
};
-class BlendSrcGeneric : public QBlendBase<uint>
+class BlendSrcGeneric : public QBlendBase
{
public:
- BlendSrcGeneric(QSpanData *d, const Operator &o)
- : QBlendBase<uint>(d, o)
+ uint *dest = nullptr;
+ alignas(16) uint buffer[BufferSize];
+ alignas(16) uint src_buffer[BufferSize];
+ BlendSrcGeneric(const QSpanData *d, const Operator &o)
+ : QBlendBase{d, o}
{
}
- const uint *fetch(int x, int y, int len)
+ const uint *fetch(int x, int y, int len, bool fetchDest)
{
- dest = op.destFetch(buffer, data->rasterBuffer, x, y, len);
+ if (fetchDest || op.destFetch == destFetchARGB32P)
+ dest = op.destFetch(buffer, data->rasterBuffer, x, y, len);
+ else
+ dest = buffer;
return op.srcFetch(src_buffer, &op, data, y, x, len);
}
@@ -3152,11 +4099,14 @@ public:
};
#if QT_CONFIG(raster_64bit)
-class BlendSrcGenericRGB64 : public QBlendBase<QRgba64>
+class BlendSrcGenericRGB64 : public QBlendBase
{
public:
- BlendSrcGenericRGB64(QSpanData *d, const Operator &o)
- : QBlendBase<QRgba64>(d, o)
+ QRgba64 *dest = nullptr;
+ alignas(16) QRgba64 buffer[BufferSize];
+ alignas(16) QRgba64 src_buffer[BufferSize];
+ BlendSrcGenericRGB64(const QSpanData *d, const Operator &o)
+ : QBlendBase{d, o}
{
}
@@ -3165,9 +4115,12 @@ public:
return op.func64 && op.destFetch64;
}
- const QRgba64 *fetch(int x, int y, int len)
+ const QRgba64 *fetch(int x, int y, int len, bool fetchDest)
{
- dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len);
+ if (fetchDest || op.destFetch64 == destFetchRGB64)
+ dest = op.destFetch64(buffer, data->rasterBuffer, x, y, len);
+ else
+ dest = buffer;
return op.srcFetch64(src_buffer, &op, data, y, x, len);
}
@@ -3184,128 +4137,251 @@ public:
};
#endif
-static void blend_src_generic(int count, const QSpan *spans, void *userData)
+#if QT_CONFIG(raster_fp)
+class BlendSrcGenericRGBFP : public QBlendBase
+{
+public:
+ QRgbaFloat32 *dest = nullptr;
+ alignas(16) QRgbaFloat32 buffer[BufferSize];
+ alignas(16) QRgbaFloat32 src_buffer[BufferSize];
+ BlendSrcGenericRGBFP(const QSpanData *d, const Operator &o)
+ : QBlendBase{d, o}
+ {
+ }
+
+ bool isSupported() const
+ {
+ return op.funcFP && op.destFetchFP && op.srcFetchFP;
+ }
+
+ const QRgbaFloat32 *fetch(int x, int y, int len, bool fetchDest)
+ {
+ if (fetchDest || op.destFetchFP == destFetchRGBFP)
+ dest = op.destFetchFP(buffer, data->rasterBuffer, x, y, len);
+ else
+ dest = buffer;
+ return op.srcFetchFP(src_buffer, &op, data, y, x, len);
+ }
+
+ void process(int, int, int len, int coverage, const QRgbaFloat32 *src, int offset)
+ {
+ op.funcFP(dest + offset, src + offset, len, coverage);
+ }
+
+ void store(int x, int y, int len)
+ {
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, y, dest, len);
+ }
+};
+#endif
+
+static void blend_src_generic(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- BlendSrcGeneric blend(data, getOperator(data, spans, count));
- handleSpans(count, spans, data, blend);
+ const Operator op = getOperator(data, nullptr, 0);
+ handleSpans<BlendSrcGeneric>(count, spans, data, op);
}
#if QT_CONFIG(raster_64bit)
-static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userData)
+static void blend_src_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- Operator op = getOperator(data, spans, count);
- BlendSrcGenericRGB64 blend64(data, op);
- if (blend64.isSupported())
- handleSpans(count, spans, data, blend64);
- else {
+ const Operator op = getOperator(data, nullptr, 0);
+ if (op.func64 && op.destFetch64) {
+ handleSpans<BlendSrcGenericRGB64>(count, spans, data, op);
+ } else {
qCDebug(lcQtGuiDrawHelper, "blend_src_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
- BlendSrcGeneric blend32(data, op);
- handleSpans(count, spans, data, blend32);
+ handleSpans<BlendSrcGeneric>(count, spans, data, op);
+ }
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void blend_src_generic_fp(int count, const QT_FT_Span *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+ const Operator op = getOperator(data, spans, count);
+ if (op.funcFP && op.destFetchFP && op.srcFetchFP) {
+ handleSpans<BlendSrcGenericRGBFP>(count, spans, data, op);
+ } else {
+ qCDebug(lcQtGuiDrawHelper, "blend_src_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
+ handleSpans<BlendSrcGeneric>(count, spans, data, op);
}
}
#endif
-static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_generic(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[BufferSize];
- uint src_buffer[BufferSize];
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
const int image_width = data->texture.width;
const int image_height = data->texture.height;
- int xoff = -qRound(-data->dx);
- int yoff = -qRound(-data->dy);
+ const int const_alpha = data->texture.const_alpha;
+ const int xoff = -qRound(-data->dx);
+ const int yoff = -qRound(-data->dy);
+ const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256 && op.destFetch != destFetchARGB32P;
- for (; count--; spans++) {
- if (!spans->len)
- continue;
- int x = spans->x;
- int length = spans->len;
- int sx = xoff + x;
- int sy = yoff + spans->y;
- if (sy >= 0 && sy < image_height && sx < image_width) {
- if (sx < 0) {
- x -= sx;
- length += sx;
- sx = 0;
- }
- if (sx + length > image_width)
- length = image_width - sx;
- if (length > 0) {
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- while (length) {
- int l = qMin(BufferSize, length);
- const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
- uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
- op.func(dest, src, l, coverage);
- if (op.destStore)
- op.destStore(data->rasterBuffer, x, spans->y, dest, l);
- x += l;
- sx += l;
- length -= l;
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ alignas(16) uint buffer[BufferSize];
+ alignas(16) uint src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ if (!spans[c].len)
+ continue;
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = xoff + x;
+ int sy = yoff + spans[c].y;
+ const bool fetchDest = !solidSource || spans[c].coverage < 255;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ const int coverage = (spans[c].coverage * const_alpha) >> 8;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
+ uint *dest = fetchDest ? op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
+ op.func(dest, src, l, coverage);
+ if (op.destStore)
+ op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ }
}
}
}
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
#if QT_CONFIG(raster_64bit)
-static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
if (!op.func64) {
qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_untransformed_generic(count, spans, userData);
}
- alignas(8) QRgba64 buffer[BufferSize];
- alignas(8) QRgba64 src_buffer[BufferSize];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
- int xoff = -qRound(-data->dx);
- int yoff = -qRound(-data->dy);
+ const int const_alpha = data->texture.const_alpha;
+ const int xoff = -qRound(-data->dx);
+ const int yoff = -qRound(-data->dy);
+ const bool solidSource = op.mode == QPainter::CompositionMode_Source && const_alpha == 256 && op.destFetch64 != destFetchRGB64;
- for (; count--; spans++) {
- if (!spans->len)
- continue;
- int x = spans->x;
- int length = spans->len;
- int sx = xoff + x;
- int sy = yoff + spans->y;
- if (sy >= 0 && sy < image_height && sx < image_width) {
- if (sx < 0) {
- x -= sx;
- length += sx;
- sx = 0;
- }
- if (sx + length > image_width)
- length = image_width - sx;
- if (length > 0) {
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- while (length) {
- int l = qMin(BufferSize, length);
- const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
- QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
- op.func64(dest, src, l, coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
- x += l;
- sx += l;
- length -= l;
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ alignas(16) QRgba64 buffer[BufferSize];
+ alignas(16) QRgba64 src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ if (!spans[c].len)
+ continue;
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = xoff + x;
+ int sy = yoff + spans[c].y;
+ const bool fetchDest = !solidSource || spans[c].coverage < 255;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ const int coverage = (spans[c].coverage * const_alpha) >> 8;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
+ QRgba64 *dest = fetchDest ? op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
+ op.func64(dest, src, l, coverage);
+ if (op.destStore64)
+ op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ }
}
}
}
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void blend_untransformed_generic_fp(int count, const QT_FT_Span *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ const Operator op = getOperator(data, spans, count);
+ if (!op.funcFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgbaf16: unsupported 4xFP16 blend attempted, falling back to 32-bit");
+ return blend_untransformed_generic(count, spans, userData);
}
+
+ const int image_width = data->texture.width;
+ const int image_height = data->texture.height;
+ const int xoff = -qRound(-data->dx);
+ const int yoff = -qRound(-data->dy);
+ const bool solidSource = op.mode == QPainter::CompositionMode_Source && data->texture.const_alpha == 256 && op.destFetchFP != destFetchRGBFP;
+
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ alignas(16) QRgbaFloat32 buffer[BufferSize];
+ alignas(16) QRgbaFloat32 src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ if (!spans[c].len)
+ continue;
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = xoff + x;
+ int sy = yoff + spans[c].y;
+ const bool fetchDest = !solidSource || spans[c].coverage < 255;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
+ while (length) {
+ int l = qMin(BufferSize, length);
+ const QRgbaFloat32 *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
+ QRgbaFloat32 *dest = fetchDest ? op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l) : buffer;
+ op.funcFP(dest, src, l, coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ }
+ }
+ }
+ }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
#endif
-static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_argb(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
@@ -3314,36 +4390,41 @@ static void blend_untransformed_argb(int count, const QSpan *spans, void *userDa
return;
}
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
const int image_width = data->texture.width;
const int image_height = data->texture.height;
- int xoff = -qRound(-data->dx);
- int yoff = -qRound(-data->dy);
+ const int const_alpha = data->texture.const_alpha;
+ const int xoff = -qRound(-data->dx);
+ const int yoff = -qRound(-data->dy);
- for (; count--; spans++) {
- if (!spans->len)
- continue;
- int x = spans->x;
- int length = spans->len;
- int sx = xoff + x;
- int sy = yoff + spans->y;
- if (sy >= 0 && sy < image_height && sx < image_width) {
- if (sx < 0) {
- x -= sx;
- length += sx;
- sx = 0;
- }
- if (sx + length > image_width)
- length = image_width - sx;
- if (length > 0) {
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
- uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
- op.func(dest, src, length, coverage);
+ auto function = [=, &op] (int cStart, int cEnd)
+ {
+ for (int c = cStart; c < cEnd; ++c) {
+ if (!spans[c].len)
+ continue;
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = xoff + x;
+ int sy = yoff + spans[c].y;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ const int coverage = (spans[c].coverage * const_alpha) >> 8;
+ const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
+ uint *dest = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + x;
+ op.func(dest, src, length, coverage);
+ }
}
}
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
static inline quint16 interpolate_pixel_rgb16_255(quint16 x, quint8 a,
@@ -3397,7 +4478,7 @@ static inline void blend_sourceOver_rgb16_rgb16(quint16 *Q_DECL_RESTRICT dest,
}
}
-static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_rgb565(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
@@ -3415,57 +4496,54 @@ static void blend_untransformed_rgb565(int count, const QSpan *spans, void *user
int xoff = -qRound(-data->dx);
int yoff = -qRound(-data->dy);
- const QSpan *end = spans + count;
- while (spans < end) {
- if (!spans->len) {
- ++spans;
- continue;
- }
- const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
- ++spans;
- continue;
- }
+ auto function = [=](int cStart, int cEnd)
+ {
+ for (int c = cStart; c < cEnd; ++c) {
+ if (!spans[c].len)
+ continue;
+ const quint8 coverage = (data->texture.const_alpha * spans[c].coverage) >> 8;
+ if (coverage == 0)
+ continue;
- int x = spans->x;
- int length = spans->len;
- int sx = xoff + x;
- int sy = yoff + spans->y;
- if (sy >= 0 && sy < image_height && sx < image_width) {
- if (sx < 0) {
- x -= sx;
- length += sx;
- sx = 0;
- }
- if (sx + length > image_width)
- length = image_width - sx;
- if (length > 0) {
- quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + x;
- const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
- if (coverage == 255) {
- memcpy(dest, src, length * sizeof(quint16));
- } else {
- const quint8 alpha = (coverage + 1) >> 3;
- const quint8 ialpha = 0x20 - alpha;
- if (alpha > 0)
- blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = xoff + x;
+ int sy = yoff + spans[c].y;
+ if (sy >= 0 && sy < image_height && sx < image_width) {
+ if (sx < 0) {
+ x -= sx;
+ length += sx;
+ sx = 0;
+ }
+ if (sx + length > image_width)
+ length = image_width - sx;
+ if (length > 0) {
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans[c].y) + x;
+ const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
+ if (coverage == 255) {
+ memcpy(dest, src, length * sizeof(quint16));
+ } else {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha > 0)
+ blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
+ }
}
}
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
-static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
+static void blend_tiled_generic(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[BufferSize];
- uint src_buffer[BufferSize];
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
const int image_width = data->texture.width;
const int image_height = data->texture.height;
+ const int const_alpha = data->texture.const_alpha;
int xoff = -qRound(-data->dx) % image_width;
int yoff = -qRound(-data->dy) % image_height;
@@ -3474,48 +4552,51 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
if (yoff < 0)
yoff += image_height;
- while (count--) {
- int x = spans->x;
- int length = spans->len;
- int sx = (xoff + spans->x) % image_width;
- int sy = (spans->y + yoff) % image_height;
- if (sx < 0)
- sx += image_width;
- if (sy < 0)
- sy += image_height;
-
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- while (length) {
- int l = qMin(image_width - sx, length);
- if (BufferSize < l)
- l = BufferSize;
- const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
- uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans->y, l);
- op.func(dest, src, l, coverage);
- if (op.destStore)
- op.destStore(data->rasterBuffer, x, spans->y, dest, l);
- x += l;
- sx += l;
- length -= l;
- if (sx >= image_width)
- sx = 0;
+ auto function = [=, &op](int cStart, int cEnd)
+ {
+ alignas(16) uint buffer[BufferSize];
+ alignas(16) uint src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = (xoff + spans[c].x) % image_width;
+ int sy = (spans[c].y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
+
+ const int coverage = (spans[c].coverage * const_alpha) >> 8;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
+ uint *dest = op.destFetch(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.func(dest, src, l, coverage);
+ if (op.destStore)
+ op.destStore(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
#if QT_CONFIG(raster_64bit)
-static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userData)
+static void blend_tiled_generic_rgb64(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
if (!op.func64) {
qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_tiled_generic(count, spans, userData);
}
- alignas(8) QRgba64 buffer[BufferSize];
- alignas(8) QRgba64 src_buffer[BufferSize];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -3530,6 +4611,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
bool isBpp64 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP64;
if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && (isBpp32 || isBpp64)) {
+ alignas(16) QRgba64 src_buffer[BufferSize];
// If destination isn't blended into the result, we can do the tiling directly on destination pixels.
while (count--) {
int x = spans->x;
@@ -3577,38 +4659,102 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
return;
}
- while (count--) {
- int x = spans->x;
- int length = spans->len;
- int sx = (xoff + spans->x) % image_width;
- int sy = (spans->y + yoff) % image_height;
- if (sx < 0)
- sx += image_width;
- if (sy < 0)
- sy += image_height;
-
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- while (length) {
- int l = qMin(image_width - sx, length);
- if (BufferSize < l)
- l = BufferSize;
- const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
- QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l);
- op.func64(dest, src, l, coverage);
- if (op.destStore64)
- op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
- x += l;
- sx += l;
- length -= l;
- if (sx >= image_width)
- sx = 0;
+ auto function = [=, &op](int cStart, int cEnd)
+ {
+ alignas(16) QRgba64 buffer[BufferSize];
+ alignas(16) QRgba64 src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = (xoff + spans[c].x) % image_width;
+ int sy = (spans[c].y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
+
+ const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l);
+ QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.func64(dest, src, l, coverage);
+ if (op.destStore64)
+ op.destStore64(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
}
- ++spans;
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
+}
+#endif
+
+#if QT_CONFIG(raster_fp)
+static void blend_tiled_generic_fp(int count, const QT_FT_Span *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ const Operator op = getOperator(data, spans, count);
+ if (!op.funcFP) {
+ qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_fp: unsupported 4xFP blend attempted, falling back to 32-bit");
+ return blend_tiled_generic(count, spans, userData);
}
+
+ const int image_width = data->texture.width;
+ const int image_height = data->texture.height;
+ int xoff = -qRound(-data->dx) % image_width;
+ int yoff = -qRound(-data->dy) % image_height;
+
+ if (xoff < 0)
+ xoff += image_width;
+ if (yoff < 0)
+ yoff += image_height;
+
+ // Consider tiling optimizing like the other versions.
+
+ auto function = [=, &op](int cStart, int cEnd)
+ {
+ alignas(16) QRgbaFloat32 buffer[BufferSize];
+ alignas(16) QRgbaFloat32 src_buffer[BufferSize];
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = (xoff + spans[c].x) % image_width;
+ int sy = (spans[c].y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
+
+ const int coverage = (spans[c].coverage * data->texture.const_alpha) >> 8;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ const QRgbaFloat32 *src = op.srcFetchFP(src_buffer, &op, data, sy, sx, l);
+ QRgbaFloat32 *dest = op.destFetchFP(buffer, data->rasterBuffer, x, spans[c].y, l);
+ op.funcFP(dest, src, l, coverage);
+ if (op.destStoreFP)
+ op.destStoreFP(data->rasterBuffer, x, spans[c].y, dest, l);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
+ }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
#endif
-static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
+static void blend_tiled_argb(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
@@ -3617,10 +4763,10 @@ static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
return;
}
- Operator op = getOperator(data, spans, count);
+ const Operator op = getOperator(data, spans, count);
- int image_width = data->texture.width;
- int image_height = data->texture.height;
+ const int image_width = data->texture.width;
+ const int image_height = data->texture.height;
int xoff = -qRound(-data->dx) % image_width;
int yoff = -qRound(-data->dy) % image_height;
@@ -3628,36 +4774,40 @@ static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
xoff += image_width;
if (yoff < 0)
yoff += image_height;
+ const auto func = op.func;
+ const int const_alpha = data->texture.const_alpha;
+
+ auto function = [=] (int cStart, int cEnd) {
+ for (int c = cStart; c < cEnd; ++c) {
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = (xoff + spans[c].x) % image_width;
+ int sy = (spans[c].y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
- while (count--) {
- int x = spans->x;
- int length = spans->len;
- int sx = (xoff + spans->x) % image_width;
- int sy = (spans->y + yoff) % image_height;
- if (sx < 0)
- sx += image_width;
- if (sy < 0)
- sy += image_height;
-
- const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
- while (length) {
- int l = qMin(image_width - sx, length);
- if (BufferSize < l)
- l = BufferSize;
- const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
- uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
- op.func(dest, src, l, coverage);
- x += l;
- sx += l;
- length -= l;
- if (sx >= image_width)
- sx = 0;
+ const int coverage = (spans[c].coverage * const_alpha) >> 8;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
+ uint *dest = ((uint *)data->rasterBuffer->scanLine(spans[c].y)) + x;
+ func(dest, src, l, coverage);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
-static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
+static void blend_tiled_rgb565(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
@@ -3680,79 +4830,80 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
if (yoff < 0)
yoff += image_height;
- while (count--) {
- const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
- ++spans;
- continue;
- }
+ const int const_alpha = data->texture.const_alpha;
+ auto function = [=] (int cStart, int cEnd) {
+ for (int c = cStart; c < cEnd; ++c) {
+ const quint8 coverage = (const_alpha * spans[c].coverage) >> 8;
+ if (coverage == 0)
+ continue;
- int x = spans->x;
- int length = spans->len;
- int sx = (xoff + spans->x) % image_width;
- int sy = (spans->y + yoff) % image_height;
- if (sx < 0)
- sx += image_width;
- if (sy < 0)
- sy += image_height;
-
- if (coverage == 255) {
- // Copy the first texture block
- length = qMin(image_width,length);
- int tx = x;
- while (length) {
- int l = qMin(image_width - sx, length);
- if (BufferSize < l)
- l = BufferSize;
- quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx;
- const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
- memcpy(dest, src, l * sizeof(quint16));
- length -= l;
- tx += l;
- sx += l;
- if (sx >= image_width)
- sx = 0;
- }
+ int x = spans[c].x;
+ int length = spans[c].len;
+ int sx = (xoff + spans[c].x) % image_width;
+ int sy = (spans[c].y + yoff) % image_height;
+ if (sx < 0)
+ sx += image_width;
+ if (sy < 0)
+ sy += image_height;
- // Now use the rasterBuffer as the source of the texture,
- // We can now progressively copy larger blocks
- // - Less cpu time in code figuring out what to copy
- // We are dealing with one block of data
- // - More likely to fit in the cache
- // - can use memcpy
- int copy_image_width = qMin(image_width, int(spans->len));
- length = spans->len - copy_image_width;
- quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
- quint16 *dest = src + copy_image_width;
- while (copy_image_width < length) {
- memcpy(dest, src, copy_image_width * sizeof(quint16));
- dest += copy_image_width;
- length -= copy_image_width;
- copy_image_width *= 2;
- }
- if (length > 0)
- memcpy(dest, src, length * sizeof(quint16));
- } else {
- const quint8 alpha = (coverage + 1) >> 3;
- const quint8 ialpha = 0x20 - alpha;
- if (alpha > 0) {
+ if (coverage == 255) {
+ // Copy the first texture block
+ length = qMin(image_width,length);
+ int tx = x;
while (length) {
int l = qMin(image_width - sx, length);
if (BufferSize < l)
l = BufferSize;
- quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
+ quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + tx;
const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
- blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
- x += l;
- sx += l;
+ memcpy(dest, src, l * sizeof(quint16));
length -= l;
+ tx += l;
+ sx += l;
if (sx >= image_width)
sx = 0;
}
+
+ // Now use the rasterBuffer as the source of the texture,
+ // We can now progressively copy larger blocks
+ // - Less cpu time in code figuring out what to copy
+ // We are dealing with one block of data
+ // - More likely to fit in the cache
+ // - can use memcpy
+ int copy_image_width = qMin(image_width, int(spans[c].len));
+ length = spans[c].len - copy_image_width;
+ quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + x;
+ quint16 *dest = src + copy_image_width;
+ while (copy_image_width < length) {
+ memcpy(dest, src, copy_image_width * sizeof(quint16));
+ dest += copy_image_width;
+ length -= copy_image_width;
+ copy_image_width *= 2;
+ }
+ if (length > 0)
+ memcpy(dest, src, length * sizeof(quint16));
+ } else {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha > 0) {
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (BufferSize < l)
+ l = BufferSize;
+ quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans[c].y)) + x;
+ const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
+ blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
+ x += l;
+ sx += l;
+ length -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
+ }
}
}
- ++spans;
- }
+ };
+ QT_THREAD_PARALLEL_FILLS(function);
}
/* Image formats here are target formats */
@@ -3794,19 +4945,30 @@ static const ProcessSpans processTextureSpansGeneric64[NBlendTypes] = {
};
#endif
-void qBlendTexture(int count, const QSpan *spans, void *userData)
+#if QT_CONFIG(raster_fp)
+static const ProcessSpans processTextureSpansGenericFP[NBlendTypes] = {
+ blend_untransformed_generic_fp, // Untransformed
+ blend_tiled_generic_fp, // Tiled
+ blend_src_generic_fp, // Transformed
+ blend_src_generic_fp, // TransformedTiled
+ blend_src_generic_fp, // TransformedBilinear
+ blend_src_generic_fp // TransformedBilinearTiled
+};
+#endif
+void qBlendTexture(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
TextureBlendType blendType = getBlendType(data);
ProcessSpans proc;
switch (data->rasterBuffer->format) {
+ case QImage::Format_Invalid:
+ Q_UNREACHABLE_RETURN();
case QImage::Format_ARGB32_Premultiplied:
proc = processTextureSpansARGB32PM[blendType];
break;
case QImage::Format_RGB16:
proc = processTextureSpansRGB16[blendType];
break;
-#if QT_CONFIG(raster_64bit)
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
case QImage::Format_ARGB32:
case QImage::Format_RGBA8888:
@@ -3819,12 +4981,28 @@ void qBlendTexture(int count, const QSpan *spans, void *userData)
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
case QImage::Format_Grayscale16:
+#if !QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+#endif
+#if QT_CONFIG(raster_64bit)
proc = processTextureSpansGeneric64[blendType];
break;
#endif // QT_CONFIG(raster_64bit)
- case QImage::Format_Invalid:
- Q_UNREACHABLE();
- return;
+#if QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ proc = processTextureSpansGenericFP[blendType];
+ break;
+#endif
default:
proc = processTextureSpansGeneric[blendType];
break;
@@ -3832,16 +5010,11 @@ void qBlendTexture(int count, const QSpan *spans, void *userData)
proc(count, spans, userData);
}
-static void blend_vertical_gradient_argb(int count, const QSpan *spans, void *userData)
+static inline bool calculate_fixed_gradient_factors(int count, const QT_FT_Span *spans,
+ const QSpanData *data,
+ const LinearGradientValues &linear,
+ int *pyinc, int *poff)
{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- LinearGradientValues linear;
- getLinearGradientValues(&linear, data);
-
- CompositionFunctionSolid funcSolid =
- functionForModeSolid[data->rasterBuffer->compositionMode];
-
/*
The logic for vertical gradient calculations is a mathematically
reduced copy of that in fetchLinearGradient() - which is basically:
@@ -3856,8 +5029,32 @@ static void blend_vertical_gradient_argb(int count, const QSpan *spans, void *us
This has then been converted to fixed point to improve performance.
*/
const int gss = GRADIENT_STOPTABLE_SIZE - 1;
- int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
- int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
+ qreal ryinc = linear.dy * data->m22 * gss * FIXPT_SIZE;
+ qreal roff = (linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss * FIXPT_SIZE;
+ const int limit = std::numeric_limits<int>::max() - FIXPT_SIZE;
+ if (count && (std::fabs(ryinc) < limit) && (std::fabs(roff) < limit)
+ && (std::fabs(ryinc * spans->y + roff) < limit)
+ && (std::fabs(ryinc * (spans + count - 1)->y + roff) < limit)) {
+ *pyinc = int(ryinc);
+ *poff = int(roff);
+ return true;
+ }
+ return false;
+}
+
+static bool blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ LinearGradientValues linear;
+ getLinearGradientValues(&linear, data);
+
+ CompositionFunctionSolid funcSolid =
+ functionForModeSolid[data->rasterBuffer->compositionMode];
+
+ int yinc(0), off(0);
+ if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
+ return false;
while (count--) {
int y = spans->y;
@@ -3870,21 +5067,20 @@ static void blend_vertical_gradient_argb(int count, const QSpan *spans, void *us
funcSolid(dst, spans->len, color, spans->coverage);
++spans;
}
+ return true;
}
template<ProcessSpans blend_color>
-static void blend_vertical_gradient(int count, const QSpan *spans, void *userData)
+static bool blend_vertical_gradient(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
LinearGradientValues linear;
getLinearGradientValues(&linear, data);
- // Based on the same logic as blend_vertical_gradient_argb.
-
- const int gss = GRADIENT_STOPTABLE_SIZE - 1;
- int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
- int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
+ int yinc(0), off(0);
+ if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
+ return false;
while (count--) {
int y = spans->y;
@@ -3892,14 +5088,15 @@ static void blend_vertical_gradient(int count, const QSpan *spans, void *userDat
#if QT_CONFIG(raster_64bit)
data->solidColor = qt_gradient_pixel64_fixed(&data->gradient, yinc * y + off);
#else
- data->solidColor = QRgba64::fromArgb32(qt_gradient_pixel_fixed(&data->gradient, yinc * y + off));
+ data->solidColor = qt_gradient_pixel_fixed(&data->gradient, yinc * y + off);
#endif
blend_color(1, spans, userData);
++spans;
}
+ return true;
}
-void qBlendGradient(int count, const QSpan *spans, void *userData)
+void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
bool isVerticalGradient =
@@ -3907,16 +5104,13 @@ void qBlendGradient(int count, const QSpan *spans, void *userData)
data->type == QSpanData::LinearGradient &&
data->gradient.linear.end.x == data->gradient.linear.origin.x;
switch (data->rasterBuffer->format) {
- case QImage::Format_RGB16:
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_rgb16>(count, spans, userData);
- return blend_src_generic(count, spans, userData);
+ case QImage::Format_Invalid:
+ break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
- if (isVerticalGradient)
- return blend_vertical_gradient_argb(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient_argb(count, spans, userData))
+ return;
return blend_src_generic(count, spans, userData);
-#if QT_CONFIG(raster_64bit)
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
case QImage::Format_ARGB32:
case QImage::Format_RGBA8888:
@@ -3928,15 +5122,33 @@ void qBlendGradient(int count, const QSpan *spans, void *userData)
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData);
+#if !QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+#endif
+#if QT_CONFIG(raster_64bit)
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData))
+ return;
return blend_src_generic_rgb64(count, spans, userData);
#endif // QT_CONFIG(raster_64bit)
- case QImage::Format_Invalid:
- break;
+#if QT_CONFIG(raster_fp)
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_fp>(count, spans, userData))
+ return;
+ return blend_src_generic_fp(count, spans, userData);
+#endif
default:
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_generic>(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic>(count, spans, userData))
+ return;
return blend_src_generic(count, spans, userData);
}
Q_UNREACHABLE();
@@ -3952,7 +5164,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
const int destStride = rasterBuffer->stride<DST>();
if (mapWidth > 8) {
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
int x0 = 0;
int n = 0;
for (int x = 0; x < mapWidth; x += 8) {
@@ -3982,7 +5194,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
map += mapStride;
}
} else {
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
int x0 = 0;
int n = 0;
for (uchar s = *map; s; s <<= 1) {
@@ -4166,7 +5378,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
const QClipData::ClipLine &line = clip->m_clipLines[yp];
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4240,7 +5452,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
const QClipData::ClipLine &line = clip->m_clipLines[yp];
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4290,7 +5502,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
if (!clip) {
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->stride<quint16>();
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i)
alphamapblend_quint16(map[i], dest, i, c);
dest += destStride;
@@ -4308,7 +5520,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(yp));
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4344,7 +5556,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i) {
const int coverage = map[i];
alphamapblend_argb32(dest + i, coverage, srcColor, c, colorProfile);
@@ -4365,7 +5577,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
quint32 *dest = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4466,7 +5678,7 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba
static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
{
// Do a gammacorrected RGB alphablend...
- const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear(dst) : dst;
QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
@@ -4545,7 +5757,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
const QClipData::ClipLine &line = clip->m_clipLines[yp];
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4618,7 +5830,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
const QClipData::ClipLine &line = clip->m_clipLines[yp];
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4662,7 +5874,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->stride<quint32>();
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i) {
const uint coverage = src[i];
alphargbblend_argb32(dst + i, coverage, srcColor, c, colorProfile);
@@ -4684,7 +5896,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
quint32 *dst = reinterpret_cast<quint32 *>(rasterBuffer->scanLine(yp));
for (int i=0; i<line.count; ++i) {
- const QSpan &clip = line.spans[i];
+ const QT_FT_Span &clip = line.spans[i];
int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
@@ -4792,10 +6004,21 @@ static void qt_rectfill_quint64(QRasterBuffer *rasterBuffer,
c64, x, y, width, height, rasterBuffer->bytesPerLine());
}
+static void qt_rectfill_fp32x4(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ const QRgba64 &color)
+{
+ const auto store = qStoreFromRGBA64PM[rasterBuffer->format];
+ QRgbaFloat32 c;
+ store(reinterpret_cast<uchar *>(&c), &color, 0, 1, nullptr, nullptr);
+ qt_rectfill<QRgbaFloat32>(reinterpret_cast<QRgbaFloat32 *>(rasterBuffer->buffer()),
+ c, x, y, width, height, rasterBuffer->bytesPerLine());
+}
+
// Map table for destination image format. Contains function pointers
// for blends of various types unto the destination
-DrawHelper qDrawHelper[QImage::NImageFormats] =
+DrawHelper qDrawHelper[] =
{
// Format_Invalid,
{ nullptr, nullptr, nullptr, nullptr, nullptr },
@@ -4840,7 +6063,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
},
// Format_RGB16
{
- blend_color_rgb16,
+ blend_color_generic,
qt_bitmapblit_quint16,
qt_alphamapblit_quint16,
qt_alphargbblit_generic,
@@ -5022,16 +6245,66 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
qt_alphargbblit_generic,
qt_rectfill_quint24
},
+ // Format_RGBX16FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBA16FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBA16FPx4_Premultiplied
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint64
+ },
+ // Format_RGBX32FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
+ // Format_RGBA32FPx4
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
+ // Format_RGBA32FPx4_Premultiplied
+ {
+ blend_color_generic_fp,
+ nullptr,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_fp32x4
+ },
};
-#if !defined(__SSE2__)
+static_assert(std::size(qDrawHelper) == QImage::NImageFormats);
+
+#if !defined(Q_PROCESSOR_X86)
void qt_memfill64(quint64 *dest, quint64 color, qsizetype count)
{
qt_memfill_template<quint64>(dest, color, count);
}
#endif
-#if defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
+#if defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
__attribute__((optimize("no-tree-vectorize")))
#endif
void qt_memfill24(quint24 *dest, quint24 color, qsizetype count)
@@ -5091,19 +6364,18 @@ void qt_memfill16(quint16 *dest, quint16 value, qsizetype count)
qt_memfill32(reinterpret_cast<quint32*>(dest), value32, count / 2);
}
-#if !defined(__SSE2__) && !defined(__ARM_NEON__) && !defined(__MIPS_DSP__)
+#if defined(Q_PROCESSOR_X86)
+void (*qt_memfill32)(quint32 *dest, quint32 value, qsizetype count) = nullptr;
+void (*qt_memfill64)(quint64 *dest, quint64 value, qsizetype count) = nullptr;
+#elif !defined(__ARM_NEON__) && !defined(__MIPS_DSP__)
void qt_memfill32(quint32 *dest, quint32 color, qsizetype count)
{
qt_memfill_template<quint32>(dest, color, count);
}
#endif
-#ifdef __SSE2__
-decltype(qt_memfill32_sse2) *qt_memfill32 = nullptr;
-decltype(qt_memfill64_sse2) *qt_memfill64 = nullptr;
-#endif
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
-template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QVector<QRgb> *, QDitherInfo *);
+template<QtPixelOrder> void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
#endif
extern void qInitBlendFunctions();
@@ -5113,8 +6385,11 @@ static void qInitDrawhelperFunctions()
// Set up basic blend function tables.
qInitBlendFunctions();
-#ifdef __SSE2__
-# ifndef __AVX2__
+#if defined(Q_PROCESSOR_X86) && !defined(__SSE2__)
+ qt_memfill32 = qt_memfill_template<quint32>;
+ qt_memfill64 = qt_memfill_template<quint64>;
+#elif defined(__SSE2__)
+# ifndef __haswell__
qt_memfill32 = qt_memfill32_sse2;
qt_memfill64 = qt_memfill64_sse2;
# endif
@@ -5193,33 +6468,35 @@ static void qInitDrawhelperFunctions()
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
if (qCpuHasFeature(SSE4_1)) {
- extern void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *);
- extern void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *);
+ extern void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *);
+ extern void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *);
extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
-# ifndef __AVX2__
+# ifndef __haswell__
qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4;
@@ -5238,10 +6515,20 @@ static void qInitDrawhelperFunctions()
qPixelLayouts[QImage::Format_A2RGB30_Premultiplied].storeFromARGB32PM = storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>;
qStoreFromRGBA64PM[QImage::Format_ARGB32] = storeARGB32FromRGBA64PM_sse4;
qStoreFromRGBA64PM[QImage::Format_RGBA8888] = storeRGBA8888FromRGBA64PM_sse4;
+ qStoreFromRGBA64PM[QImage::Format_RGBX64] = storeRGBx64FromRGBA64PM_sse4;
+ qStoreFromRGBA64PM[QImage::Format_RGBA64] = storeRGBA64FromRGBA64PM_sse4;
#if QT_CONFIG(raster_64bit)
destStoreProc64[QImage::Format_ARGB32] = destStore64ARGB32_sse4;
destStoreProc64[QImage::Format_RGBA8888] = destStore64RGBA8888_sse4;
#endif
+#if QT_CONFIG(raster_fp)
+ extern const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F_sse4(QRgbaFloat32 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBX32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qFetchToRGBA32F[QImage::Format_RGBA32FPx4] = fetchRGBA32FToRGBA32F_sse4;
+ qStoreFromRGBA32F[QImage::Format_RGBX32FPx4] = storeRGBX32FFromRGBA32F_sse4;
+ qStoreFromRGBA32F[QImage::Format_RGBA32FPx4] = storeRGBA32FFromRGBA32F_sse4;
+#endif // QT_CONFIG(raster_fp)
}
#endif
@@ -5278,6 +6565,16 @@ static void qInitDrawhelperFunctions()
qt_functionForMode64_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgb64_avx2;
qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2;
#endif
+#if QT_CONFIG(raster_fp)
+ extern void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgbaFloat32 *destPixels, const QRgbaFloat32 *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgbaFloat32 *destPixels, const QRgbaFloat32 *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgbaFloat32 *destPixels, int length, QRgbaFloat32 color, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgbaFloat32 *destPixels, int length, QRgbaFloat32 color, uint const_alpha);
+ qt_functionForModeFP_C[QPainter::CompositionMode_Source] = comp_func_Source_rgbafp_avx2;
+ qt_functionForModeFP_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_rgbafp_avx2;
+ qt_functionForModeSolidFP_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_rgbafp_avx2;
+ qt_functionForModeSolidFP_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgbafp_avx2;
+#endif
extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
int &fx, int &fy, int fdx, int /*fdy*/);
@@ -5290,28 +6587,56 @@ static void qInitDrawhelperFunctions()
bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2;
bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2;
- extern void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *);
- extern void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *);
+ extern void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *);
+ extern void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *);
extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_avx2;
qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2;
qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_avx2;
qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2;
-#if QT_CONFIG(raster_64bit)
- extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QVector<QRgb> *, QDitherInfo *);
- extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QVector<QRgb> *, QDitherInfo *);
- extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *);
- extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QVector<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *, const uint *, int, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uint *, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *, const uchar *, int, int, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
qPixelLayouts[QImage::Format_ARGB32].convertToRGBA64PM = convertARGB32ToRGBA64PM_avx2;
qPixelLayouts[QImage::Format_RGBX8888].convertToRGBA64PM = convertRGBA8888ToRGBA64PM_avx2;
qPixelLayouts[QImage::Format_ARGB32].fetchToRGBA64PM = fetchARGB32ToRGBA64PM_avx2;
qPixelLayouts[QImage::Format_RGBX8888].fetchToRGBA64PM = fetchRGBA8888ToRGBA64PM_avx2;
-#endif
+ qPixelLayouts[QImage::Format_RGBA64].fetchToRGBA64PM = fetchRGBA64ToRGBA64PM_avx2;
+
+ extern const uint *QT_FASTCALL fetchRGB16FToRGB32_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const uint *QT_FASTCALL fetchRGBA16FToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGB16FFromRGB32_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBX16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToARGB32PM = fetchRGBA16FToARGB32PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].fetchToRGBA64PM = fetchRGBA16FToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromARGB32PM = storeRGBA16FFromARGB32PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToARGB32PM = fetchRGB16FToRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].fetchToRGBA64PM = fetchRGBA16FPMToRGBA64PM_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromARGB32PM = storeRGB16FFromRGB32_avx2;
+ qPixelLayouts[QImage::Format_RGBA16FPx4_Premultiplied].storeFromRGB32 = storeRGB16FFromRGB32_avx2;
+#if QT_CONFIG(raster_fp)
+ extern const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgbaFloat32 *buffer, const uchar *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ extern void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count, const QList<QRgb> *, QDitherInfo *);
+ qFetchToRGBA32F[QImage::Format_RGBA16FPx4] = fetchRGBA16FToRGBA32F_avx2;
+ qStoreFromRGBA32F[QImage::Format_RGBX16FPx4] = storeRGBX16FFromRGBA32F_avx2;
+ qStoreFromRGBA32F[QImage::Format_RGBA16FPx4] = storeRGBA16FFromRGBA32F_avx2;
+#endif // QT_CONFIG(raster_fp)
}
+
#endif
#endif // SSE2
@@ -5340,26 +6665,26 @@ static void qInitDrawhelperFunctions()
sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_neon;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- extern void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *);
- extern void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *);
+ extern void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *);
+ extern void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *);
extern const uint *QT_FASTCALL fetchARGB32ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+ const QList<QRgb> *, QDitherInfo *);
qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_neon;
qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon;
qPixelLayouts[QImage::Format_ARGB32].storeFromARGB32PM = storeARGB32FromARGB32PM_neon;
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index 1f6be21f50..34de69ecf4 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdrawhelper_p.h"
#include "qdrawhelper_x86_p.h"
@@ -143,7 +107,6 @@ INTERPOLATE_PIXEL_RGB64_AVX2(__m256i srcVector, __m256i &dstVector, __m256i alph
dstVector = _mm256_or_si256(finalAG, finalRB);
}
-
// See BLEND_SOURCE_OVER_ARGB32_SSE2 for details.
inline static void Q_DECL_VECTORCALL BLEND_SOURCE_OVER_ARGB32_AVX2(quint32 *dst, const quint32 *src, const int length)
{
@@ -360,7 +323,7 @@ void Q_DECL_VECTORCALL qt_memfillXX_avx2(uchar *dest, __m256i value256, qsizetyp
void qt_memfill64_avx2(quint64 *dest, quint64 value, qsizetype count)
{
-#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
+#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
// work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80820
__m128i value64 = _mm_set_epi64x(0, value); // _mm_cvtsi64_si128(value);
# ifdef Q_PROCESSOR_X86_64
@@ -457,6 +420,40 @@ void QT_FASTCALL comp_func_SourceOver_rgb64_avx2(QRgba64 *dst, const QRgba64 *sr
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgbaFloat32 *dst, const QRgbaFloat32 *src, int length, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+
+ const float a = const_alpha / 255.0f;
+ const __m128 one = _mm_set1_ps(1.0f);
+ const __m128 constAlphaVector = _mm_set1_ps(a);
+ const __m256 one256 = _mm256_set1_ps(1.0f);
+ const __m256 constAlphaVector256 = _mm256_set1_ps(a);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 srcVector = _mm256_loadu_ps((const float *)&src[x]);
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm256_mul_ps(srcVector, constAlphaVector256);
+ __m256 alphaChannel = _mm256_permute_ps(srcVector, _MM_SHUFFLE(3, 3, 3, 3));
+ alphaChannel = _mm256_sub_ps(one256, alphaChannel);
+ dstVector = _mm256_mul_ps(dstVector, alphaChannel);
+ dstVector = _mm256_add_ps(dstVector, srcVector);
+ _mm256_storeu_ps((float *)(dst + x), dstVector);
+ }
+ if (x < length) {
+ __m128 srcVector = _mm_loadu_ps((const float *)&src[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm_mul_ps(srcVector, constAlphaVector);
+ __m128 alphaChannel = _mm_permute_ps(srcVector, _MM_SHUFFLE(3, 3, 3, 3));
+ alphaChannel = _mm_sub_ps(one, alphaChannel);
+ dstVector = _mm_mul_ps(dstVector, alphaChannel);
+ dstVector = _mm_add_ps(dstVector, srcVector);
+ _mm_storeu_ps((float *)(dst + x), dstVector);
+ }
+}
+#endif
+
void QT_FASTCALL comp_func_Source_avx2(uint *dst, const uint *src, int length, uint const_alpha)
{
if (const_alpha == 255) {
@@ -523,6 +520,41 @@ void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, i
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgbaFloat32 *dst, const QRgbaFloat32 *src, int length, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255) {
+ ::memcpy(dst, src, length * sizeof(QRgbaFloat32));
+ } else {
+ const float ca = const_alpha / 255.f;
+ const float cia = 1.0f - ca;
+
+ const __m128 constAlphaVector = _mm_set1_ps(ca);
+ const __m128 oneMinusConstAlpha = _mm_set1_ps(cia);
+ const __m256 constAlphaVector256 = _mm256_set1_ps(ca);
+ const __m256 oneMinusConstAlpha256 = _mm256_set1_ps(cia);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 srcVector = _mm256_loadu_ps((const float *)&src[x]);
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm256_mul_ps(srcVector, constAlphaVector256);
+ dstVector = _mm256_mul_ps(dstVector, oneMinusConstAlpha256);
+ dstVector = _mm256_add_ps(dstVector, srcVector);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 srcVector = _mm_loadu_ps((const float *)&src[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
+ srcVector = _mm_mul_ps(srcVector, constAlphaVector);
+ dstVector = _mm_mul_ps(dstVector, oneMinusConstAlpha);
+ dstVector = _mm_add_ps(dstVector, srcVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+#endif
+
void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, uint color, uint const_alpha)
{
if ((const_alpha & qAlpha(color)) == 255) {
@@ -587,6 +619,69 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int
}
#endif
+#if QT_CONFIG(raster_fp)
+void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgbaFloat32 *dst, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255) {
+ for (int i = 0; i < length; ++i)
+ dst[i] = color;
+ } else {
+ const float a = const_alpha / 255.0f;
+ const __m128 alphaVector = _mm_set1_ps(a);
+ const __m128 minusAlphaVector = _mm_set1_ps(1.0f - a);
+ __m128 colorVector = _mm_loadu_ps((const float *)&color);
+ colorVector = _mm_mul_ps(colorVector, alphaVector);
+ const __m256 colorVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(colorVector), colorVector, 1);
+ const __m256 minusAlphaVector256 = _mm256_set1_ps(1.0f - a);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm256_mul_ps(dstVector, minusAlphaVector256);
+ dstVector = _mm256_add_ps(dstVector, colorVector256);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm_mul_ps(dstVector, minusAlphaVector);
+ dstVector = _mm_add_ps(dstVector, colorVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+
+void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgbaFloat32 *dst, int length, QRgbaFloat32 color, uint const_alpha)
+{
+ Q_ASSERT(const_alpha < 256); // const_alpha is in [0-255]
+ if (const_alpha == 255 && color.a >= 1.0f) {
+ for (int i = 0; i < length; ++i)
+ dst[i] = color;
+ } else {
+ __m128 colorVector = _mm_loadu_ps((const float *)&color);
+ if (const_alpha != 255)
+ colorVector = _mm_mul_ps(colorVector, _mm_set1_ps(const_alpha / 255.f));
+ __m128 minusAlphaOfColorVector =
+ _mm_sub_ps(_mm_set1_ps(1.0f), _mm_permute_ps(colorVector, _MM_SHUFFLE(3, 3, 3, 3)));
+ const __m256 colorVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(colorVector), colorVector, 1);
+ const __m256 minusAlphaVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(minusAlphaOfColorVector),
+ minusAlphaOfColorVector, 1);
+ int x = 0;
+ for (; x < length - 1; x += 2) {
+ __m256 dstVector = _mm256_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm256_mul_ps(dstVector, minusAlphaVector256);
+ dstVector = _mm256_add_ps(dstVector, colorVector256);
+ _mm256_storeu_ps((float *)&dst[x], dstVector);
+ }
+ if (x < length) {
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
+ dstVector = _mm_mul_ps(dstVector, minusAlphaOfColorVector);
+ dstVector = _mm_add_ps(dstVector, colorVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
+ }
+ }
+}
+#endif
+
#define interpolate_4_pixels_16_avx2(tlr1, tlr2, blr1, blr2, distx, disty, colorMask, v_256, b) \
{ \
/* Correct for later unpack */ \
@@ -1089,25 +1184,25 @@ static void convertARGBToARGB32PM_avx2(uint *buffer, const uint *src, qsizetype
}
}
-void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *)
+void QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_avx2<false>(buffer, buffer, count);
}
-void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QVector<QRgb> *)
+void QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_avx2<true>(buffer, buffer, count);
}
const uint *QT_FASTCALL fetchARGB32ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_avx2<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_avx2<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
@@ -1202,33 +1297,320 @@ static void convertARGBToRGBA64PM_avx2(QRgba64 *buffer, const uint *src, qsizety
}
const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_avx2(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_avx2<false>(buffer, src, count);
return buffer;
}
const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_avx2(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_avx2<true>(buffer, src, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_avx2<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_avx2<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
+const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ int i = 0;
+ const __m256i vh = _mm256_set1_epi32(0x8000);
+ for (; i < count - 3; i += 4) {
+ __m256i vs256 = _mm256_loadu_si256((const __m256i *)(s + i));
+ __m256i va256 = _mm256_shufflelo_epi16(vs256, _MM_SHUFFLE(3, 3, 3, 3));
+ va256 = _mm256_shufflehi_epi16(va256, _MM_SHUFFLE(3, 3, 3, 3));
+ const __m256i vmullo = _mm256_mullo_epi16(vs256, va256);
+ const __m256i vmulhi = _mm256_mulhi_epu16(vs256, va256);
+ __m256i vslo = _mm256_unpacklo_epi16(vmullo, vmulhi);
+ __m256i vshi = _mm256_unpackhi_epi16(vmullo, vmulhi);
+ vslo = _mm256_add_epi32(vslo, _mm256_srli_epi32(vslo, 16));
+ vshi = _mm256_add_epi32(vshi, _mm256_srli_epi32(vshi, 16));
+ vslo = _mm256_add_epi32(vslo, vh);
+ vshi = _mm256_add_epi32(vshi, vh);
+ vslo = _mm256_srli_epi32(vslo, 16);
+ vshi = _mm256_srli_epi32(vshi, 16);
+ vs256 = _mm256_packus_epi32(vslo, vshi);
+ vs256 = _mm256_blend_epi16(vs256, va256, 0x88);
+ _mm256_storeu_si256((__m256i *)(buffer + i), vs256);
+ }
+ for (; i < count; ++i) {
+ const auto a = s[i].alpha();
+ __m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
+ __m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
+ vs = multiplyAlpha65535(vs, va);
+ _mm_storel_epi64((__m128i *)(buffer + i), vs);
+ buffer[i].setAlpha(a);
+ }
+ return buffer;
+}
+
+const uint *QT_FASTCALL fetchRGB16FToRGB32_avx2(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(255.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packs_epi32(vsi, vsi);
+ vsi = _mm256_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i vsi128 = _mm256_castsi256_si128(vsi);
+ vsi128 = _mm_packus_epi16(vsi128, vsi128);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi128);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(255.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packs_epi32(vsi, vsi);
+ vsi = _mm_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm_packus_epi16(vsi, vsi);
+ buffer[i] = _mm_cvtsi128_si32(vsi);
+ }
+ return buffer;
+}
+
+const uint *QT_FASTCALL fetchRGBA16FToARGB32PM_avx2(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(255.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i vsi128 = _mm256_castsi256_si128(vsi);
+ vsi128 = _mm_packus_epi16(vsi128, vsi128);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi128);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(255.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ vsi = _mm_shufflelo_epi16(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ vsi = _mm_packus_epi16(vsi, vsi);
+ buffer[i] = _mm_cvtsi128_si32(vsi);
+ }
+ return buffer;
+}
+
+const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(65535.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ _mm_storeu_si128((__m128i *)(buffer + i), _mm256_castsi256_si128(vsi));
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(65535.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi);
+ }
+ return buffer;
+}
+
+const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM_avx2(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ const __m256 vf = _mm256_set1_ps(65535.0f);
+ const __m256 vh = _mm256_set1_ps(0.5f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ vsf = _mm256_mul_ps(vsf, vf);
+ vsf = _mm256_add_ps(vsf, vh);
+ __m256i vsi = _mm256_cvttps_epi32(vsf);
+ vsi = _mm256_packus_epi32(vsi, vsi);
+ vsi = _mm256_permute4x64_epi64(vsi, _MM_SHUFFLE(3, 1, 2, 0));
+ _mm_storeu_si128((__m128i *)(buffer + i), _mm256_castsi256_si128(vsi));
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(65535.0f));
+ vsf = _mm_add_ps(vsf, _mm_set1_ps(0.5f));
+ __m128i vsi = _mm_cvttps_epi32(vsf);
+ vsi = _mm_packus_epi32(vsi, vsi);
+ _mm_storel_epi64((__m128i *)(buffer + i), vsi);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGB16FFromRGB32_avx2(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m256 vf = _mm256_set1_ps(1.0f / 255.0f);
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256i vsi = _mm256_cvtepu8_epi32(_mm_loadl_epi64((const __m128i *)(src + i)));
+ vsi = _mm256_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m256 vsf = _mm256_cvtepi32_ps(vsi);
+ vsf = _mm256_mul_ps(vsf, vf);
+ _mm_storeu_si128((__m128i *)(d + i), _mm256_cvtps_ph(vsf, 0));
+ }
+ if (i < count) {
+ __m128i vsi = _mm_cvtsi32_si128(src[i]);
+ vsi = _mm_cvtepu8_epi32(vsi);
+ vsi = _mm_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128 vsf = _mm_cvtepi32_ps(vsi);
+ vsf = _mm_mul_ps(vsf, _mm_set1_ps(1.0f / 255.0f));
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+void QT_FASTCALL storeRGBA16FFromARGB32PM_avx2(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 vf = _mm_set1_ps(1.0f / 255.0f);
+ for (int i = 0; i < count; ++i) {
+ const uint s = src[i];
+ __m128i vsi = _mm_cvtsi32_si128(s);
+ vsi = _mm_cvtepu8_epi32(vsi);
+ vsi = _mm_shuffle_epi32(vsi, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128 vsf = _mm_cvtepi32_ps(vsi);
+ const uint8_t a = (s >> 24);
+ if (a == 255)
+ vsf = _mm_mul_ps(vsf, vf);
+ else if (a == 0)
+ vsf = _mm_set1_ps(0.0f);
+ else {
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+#if QT_CONFIG(raster_fp)
+const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const quint64 *s = reinterpret_cast<const quint64 *>(src) + index;
+ int i = 0;
+ for (; i + 1 < count; i += 2) {
+ __m256 vsf = _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(s + i)));
+ __m256 vsa = _mm256_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm256_mul_ps(vsf, vsa);
+ vsf = _mm256_blend_ps(vsf, vsa, 0x88);
+ _mm256_storeu_ps((float *)(buffer + i), vsf);
+ }
+ if (i < count) {
+ __m128 vsf = _mm_cvtph_ps(_mm_loadl_epi64((const __m128i *)(s + i)));
+ __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ _mm_storeu_ps((float *)(buffer + i), vsf);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 *s = reinterpret_cast<const __m128 *>(src);
+ const __m128 zero = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_loadu_ps(reinterpret_cast<const float *>(s + i));
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsf = _mm_mul_ps(vsf, vsr);
+ vsf = _mm_insert_ps(vsf, _mm_set_ss(1.0f), 0x30);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+
+void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint64 *d = reinterpret_cast<quint64 *>(dest) + index;
+ const __m128 *s = reinterpret_cast<const __m128 *>(src);
+ const __m128 zero = _mm_set1_ps(0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_loadu_ps(reinterpret_cast<const float *>(s + i));
+ const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_storel_epi64((__m128i *)(d + i), _mm_cvtps_ph(vsf, 0));
+ }
+}
+#endif
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/painting/qdrawhelper_mips_dsp.cpp b/src/gui/painting/qdrawhelper_mips_dsp.cpp
index 17597deb1d..86dcde2b58 100644
--- a/src/gui/painting/qdrawhelper_mips_dsp.cpp
+++ b/src/gui/painting/qdrawhelper_mips_dsp.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qdrawhelper_p.h>
#include <private/qdrawhelper_mips_dsp_p.h>
@@ -131,7 +95,7 @@ void qt_blend_rgb16_on_rgb16_mips_dspr2(uchar *destPixels, int dbpl,
}
else {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(destPixels, srcPixels, length);
destPixels += dbpl;
srcPixels += sbpl;
@@ -166,7 +130,7 @@ void qt_blend_rgb16_on_rgb16_mips_dsp(uchar *destPixels, int dbpl,
}
else {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(destPixels, srcPixels, length);
destPixels += dbpl;
srcPixels += sbpl;
diff --git a/src/gui/painting/qdrawhelper_mips_dsp_asm.S b/src/gui/painting/qdrawhelper_mips_dsp_asm.S
index c6b34293b6..8e0530aa9d 100644
--- a/src/gui/painting/qdrawhelper_mips_dsp_asm.S
+++ b/src/gui/painting/qdrawhelper_mips_dsp_asm.S
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qt_mips_asm_dsp_p.h"
@@ -1970,7 +1934,7 @@ LEAF_MIPS_DSP(fetchUntransformed_444_asm_mips_dsp)
2:
andi t0, a1, 0x3
beqz t0, 3f /* memory is word aligned */
- andi a3, a2, 0x1 /* set the a3 register as the comparation
+ andi a3, a2, 0x1 /* set the a3 register as the comparison
* for ending the unrolled loop
* (1 if odd, 0 if even) */
b 1b /* not word aligned,
diff --git a/src/gui/painting/qdrawhelper_mips_dsp_p.h b/src/gui/painting/qdrawhelper_mips_dsp_p.h
index a3d0410274..2a371b3b46 100644
--- a/src/gui/painting/qdrawhelper_mips_dsp_p.h
+++ b/src/gui/painting/qdrawhelper_mips_dsp_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDRAWHELPER_MIPS_DSP_P_H
#define QDRAWHELPER_MIPS_DSP_P_H
diff --git a/src/gui/painting/qdrawhelper_mips_dspr2_asm.S b/src/gui/painting/qdrawhelper_mips_dspr2_asm.S
index 4921365e36..edcaa5d0a9 100644
--- a/src/gui/painting/qdrawhelper_mips_dspr2_asm.S
+++ b/src/gui/painting/qdrawhelper_mips_dspr2_asm.S
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qt_mips_asm_dsp_p.h"
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index 3cb01ba5ac..1fceb83710 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qdrawhelper_neon_p.h>
#include <private/qblendfunctions_p.h>
@@ -221,7 +185,7 @@ void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl,
quint8 a = (255 * const_alpha) >> 8;
quint8 ia = 255 - a;
- while (h--) {
+ while (--h >= 0) {
for (int x=0; x<w; ++x)
dst[x] = INTERPOLATE_PIXEL_255(qConvertRgb16To32(src[x]), a, dst[x], ia);
dst += dbpl;
@@ -264,7 +228,7 @@ static inline void blockBlit16(quint16 *dst, quint16 *src, int dstride, int sstr
u.pointer = dst;
if (u.address & 2) {
- while (h--) {
+ while (--h >= 0) {
// align dst
dst[0] = src[0];
if (Width > 1)
@@ -273,7 +237,7 @@ static inline void blockBlit16(quint16 *dst, quint16 *src, int dstride, int sstr
src += sstride;
}
} else {
- while (h--) {
+ while (--h >= 0) {
scanLineBlit16<Width>(dst, src, dstride);
dst += dstride;
@@ -1312,81 +1276,81 @@ static inline void convertARGBFromARGB32PM_neon(uint *buffer, const uint *src, i
}
}
-void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *)
+void QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_neon<false>(buffer, buffer, count);
}
-void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QVector<QRgb> *)
+void QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_neon<true>(buffer, buffer, count);
}
const uint *QT_FASTCALL fetchARGB32ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_neon<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_neon(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_neon<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGB32ToRGBA64PM_neon<false>(buffer, src, count);
return buffer;
}
const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGB32ToRGBA64PM_neon<true>(buffer, src, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGB32ToRGBA64PM_neon<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_neon(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGB32ToRGBA64PM_neon<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
void QT_FASTCALL storeRGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_neon<false,true>(d, src, count);
}
void QT_FASTCALL storeARGB32FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_neon<false,false>(d, src, count);
}
void QT_FASTCALL storeRGBA8888FromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_neon<true,false>(d, src, count);
}
void QT_FASTCALL storeRGBXFromARGB32PM_neon(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_neon<true,true>(d, src, count);
diff --git a/src/gui/painting/qdrawhelper_neon_asm.S b/src/gui/painting/qdrawhelper_neon_asm.S
index 1830fd2fc0..3b6568403f 100644
--- a/src/gui/painting/qdrawhelper_neon_asm.S
+++ b/src/gui/painting/qdrawhelper_neon_asm.S
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if defined(ENABLE_PIXMAN_DRAWHELPERS)
@@ -296,4 +260,4 @@ qt_rotate90_16_neon:
.endfunc
-#endif \ No newline at end of file
+#endif
diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h
index 19e1f21a3b..193499f223 100644
--- a/src/gui/painting/qdrawhelper_neon_p.h
+++ b/src/gui/painting/qdrawhelper_neon_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDRAWHELPER_NEON_P_H
#define QDRAWHELPER_NEON_P_H
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 13629f1fea..833ddd7b16 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDRAWHELPER_P_H
#define QDRAWHELPER_P_H
@@ -65,13 +29,13 @@
#include "private/qrasterdefs_p.h"
#include <private/qsimd_p.h>
-#include <QtCore/qsharedpointer.h>
+#include <memory>
QT_BEGIN_NAMESPACE
#if defined(Q_CC_GNU)
# define Q_DECL_RESTRICT __restrict__
-# if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL)
+# if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
# define Q_DECL_VECTORCALL __attribute__((sseregparm,regparm(3)))
# else
# define Q_DECL_VECTORCALL
@@ -89,13 +53,6 @@ static const uint RMASK = 0x00ff0000;
static const uint GMASK = 0x0000ff00;
static const uint BMASK = 0x000000ff;
-/*******************************************************************************
- * QSpan
- *
- * duplicate definition of FT_Span
- */
-typedef QT_FT_Span QSpan;
-
struct QSolidData;
struct QTextureData;
struct QGradientData;
@@ -108,6 +65,9 @@ class QRasterBuffer;
class QClipData;
class QRasterPaintEngineState;
+template<typename F> class QRgbaFloat;
+typedef QRgbaFloat<float> QRgbaFloat32;
+
typedef QT_FT_SpanFunc ProcessSpans;
typedef void (*BitmapBlitFunc)(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
@@ -180,9 +140,9 @@ struct quint24 {
uchar data[3];
};
-void qBlendGradient(int count, const QSpan *spans, void *userData);
-void qBlendTexture(int count, const QSpan *spans, void *userData);
-#ifdef __SSE2__
+void qBlendGradient(int count, const QT_FT_Span *spans, void *userData);
+void qBlendTexture(int count, const QT_FT_Span *spans, void *userData);
+#ifdef Q_PROCESSOR_X86
extern void (*qt_memfill64)(quint64 *dest, quint64 value, qsizetype count);
extern void (*qt_memfill32)(quint32 *dest, quint32 value, qsizetype count);
#else
@@ -194,8 +154,10 @@ extern void qt_memfill16(quint16 *dest, quint16 value, qsizetype count);
typedef void (QT_FASTCALL *CompositionFunction)(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunction64)(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha);
+typedef void (QT_FASTCALL *CompositionFunctionFP)(QRgbaFloat32 *Q_DECL_RESTRICT dest, const QRgbaFloat32 *Q_DECL_RESTRICT src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid64)(QRgba64 *dest, int length, QRgba64 color, uint const_alpha);
+typedef void (QT_FASTCALL *CompositionFunctionSolidFP)(QRgbaFloat32 *dest, int length, QRgbaFloat32 color, uint const_alpha);
struct LinearGradientValues
{
@@ -212,17 +174,19 @@ struct RadialGradientValues
qreal dr;
qreal sqrfr;
qreal a;
- qreal inv2a;
bool extended;
};
struct Operator;
typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
typedef QRgba64* (QT_FASTCALL *DestFetchProc64)(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
+typedef QRgbaFloat32* (QT_FASTCALL *DestFetchProcFP)(QRgbaFloat32 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
typedef void (QT_FASTCALL *DestStoreProc64)(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
+typedef void (QT_FASTCALL *DestStoreProcFP)(QRasterBuffer *rasterBuffer, int x, int y, const QRgbaFloat32 *buffer, int length);
typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
typedef const QRgba64* (QT_FASTCALL *SourceFetchProc64)(QRgba64 *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
+typedef const QRgbaFloat32* (QT_FASTCALL *SourceFetchProcFP)(QRgbaFloat32 *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
struct Operator
{
@@ -239,6 +203,12 @@ struct Operator
CompositionFunctionSolid64 funcSolid64;
CompositionFunction64 func64;
+ DestFetchProcFP destFetchFP;
+ DestStoreProcFP destStoreFP;
+ SourceFetchProcFP srcFetchFP;
+ CompositionFunctionSolidFP funcSolidFP;
+ CompositionFunctionFP funcFP;
+
union {
LinearGradientValues linear;
RadialGradientValues radial;
@@ -295,7 +265,7 @@ struct QGradientData
#define GRADIENT_STOPTABLE_SIZE 1024
#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
const QRgba64 *colorTable64; //[GRADIENT_STOPTABLE_SIZE];
#endif
const QRgb *colorTable32; //[GRADIENT_STOPTABLE_SIZE];
@@ -321,7 +291,8 @@ struct QTextureData
bool hasAlpha;
enum Type {
Plain,
- Tiled
+ Tiled,
+ Pattern
};
Type type;
int const_alpha;
@@ -349,24 +320,20 @@ struct QSpanData
ConicalGradient,
Texture
} type : 8;
- int txop : 8;
- int fast_matrix : 1;
+ signed int txop : 8;
+ uint fast_matrix : 1;
bool bilinear;
QImage *tempImage;
- QRgba64 solidColor;
+ QColor solidColor;
union {
QGradientData gradient;
QTextureData texture;
};
- class Pinnable {
- protected:
- ~Pinnable() {}
- }; // QSharedPointer<const void> is not supported
- QSharedPointer<const Pinnable> cachedGradient;
+ std::shared_ptr<const void> cachedGradient;
void init(QRasterBuffer *rb, const QRasterPaintEngine *pe);
- void setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode);
+ void setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode, bool isCosmetic);
void setupMatrix(const QTransform &matrix, int bilinear);
void initTexture(const QImage *image, int alpha, QTextureData::Type = QTextureData::Plain, const QRect &sourceRect = QRect());
void adjustSpanMethods();
@@ -434,12 +401,12 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
bool affine = !data->m13 && !data->m23;
BlendType *end = buffer + length;
+ qreal inv_a = 1 / qreal(2 * op->radial.a);
+
if (affine) {
rx -= data->gradient.radial.focal.x;
ry -= data->gradient.radial.focal.y;
- qreal inv_a = 1 / qreal(2 * op->radial.a);
-
const qreal delta_rx = data->m11;
const qreal delta_ry = data->m12;
@@ -472,7 +439,7 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
while (buffer < end) {
if (rw == 0) {
- *buffer = 0;
+ *buffer = RadialFetchFunc::null();
} else {
qreal invRw = 1 / rw;
qreal gx = rx * invRw - data->gradient.radial.focal.x;
@@ -484,8 +451,8 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
if (det >= 0) {
qreal detSqrt = qSqrt(det);
- qreal s0 = (-b - detSqrt) * op->radial.inv2a;
- qreal s1 = (-b + detSqrt) * op->radial.inv2a;
+ qreal s0 = (-b - detSqrt) * inv_a;
+ qreal s1 = (-b + detSqrt) * inv_a;
qreal s = qMax(s0, s1);
@@ -605,7 +572,7 @@ public:
}
};
-static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) {
+static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) {
uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
t &= 0xff00ff;
@@ -619,7 +586,7 @@ static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b
#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit versions
-static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
+static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
t += (((quint64(y)) | ((quint64(y)) << 24)) & 0x00ff00ff00ff00ff) * b;
t >>= 8;
@@ -627,7 +594,7 @@ static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b
return (uint(t)) | (uint(t >> 24));
}
-static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
+static inline uint BYTE_MUL(uint x, uint a) {
quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8;
t &= 0x00ff00ff00ff00ff;
@@ -636,7 +603,7 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
#else // 32-bit versions
-static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
+static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) {
uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
t >>= 8;
t &= 0xff00ff;
@@ -647,7 +614,7 @@ static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b
return x;
}
-static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
+static inline uint BYTE_MUL(uint x, uint a) {
uint t = (x & 0xff00ff) * a;
t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
t &= 0xff00ff;
@@ -660,7 +627,7 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) {
}
#endif
-static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src)
+static inline void blend_pixel(quint32 &dst, const quint32 src)
{
if (src >= 0xff000000)
dst = src;
@@ -668,7 +635,7 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src)
dst = src + BYTE_MUL(dst, qAlpha(~src));
}
-static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha)
+static inline void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha)
{
if (const_alpha == 255)
return blend_pixel(dst, src);
@@ -679,7 +646,7 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const i
}
#if defined(__SSE2__)
-static Q_ALWAYS_INLINE uint interpolate_4_pixels_sse2(__m128i vt, __m128i vb, uint distx, uint disty)
+static inline uint Q_DECL_VECTORCALL interpolate_4_pixels_sse2(__m128i vt, __m128i vb, uint distx, uint disty)
{
// First interpolate top and bottom pixels in parallel.
vt = _mm_unpacklo_epi8(vt, _mm_setzero_si128());
@@ -720,7 +687,7 @@ static inline uint interpolate_4_pixels(const uint t[], const uint b[], uint dis
static constexpr inline bool hasFastInterpolate4() { return true; }
#elif defined(__ARM_NEON__)
-static Q_ALWAYS_INLINE uint interpolate_4_pixels_neon(uint32x2_t vt32, uint32x2_t vb32, uint distx, uint disty)
+static inline uint interpolate_4_pixels_neon(uint32x2_t vt32, uint32x2_t vb32, uint distx, uint disty)
{
uint16x8_t vt16 = vmovl_u8(vreinterpret_u8_u32(vt32));
uint16x8_t vb16 = vmovl_u8(vreinterpret_u8_u32(vb32));
@@ -844,24 +811,75 @@ static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba6
}
#endif // __SSE2__
-static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16(uint x, uint a) {
+#if QT_CONFIG(raster_fp)
+static inline QRgbaFloat32 multiplyAlpha_rgba32f(QRgbaFloat32 c, float a)
+{
+ return QRgbaFloat32 { c.r * a, c.g * a, c.b * a, c.a * a };
+}
+
+static inline QRgbaFloat32 interpolate_rgba32f(QRgbaFloat32 x, float alpha1, QRgbaFloat32 y, float alpha2)
+{
+ x = multiplyAlpha_rgba32f(x, alpha1);
+ y = multiplyAlpha_rgba32f(y, alpha2);
+ return QRgbaFloat32 { x.r + y.r, x.g + y.g, x.b + y.b, x.a + y.a };
+}
+#ifdef __SSE2__
+static inline __m128 Q_DECL_VECTORCALL interpolate_rgba32f(__m128 x, __m128 alpha1, __m128 y, __m128 alpha2)
+{
+ return _mm_add_ps(_mm_mul_ps(x, alpha1), _mm_mul_ps(y, alpha2));
+}
+#endif
+
+static inline QRgbaFloat32 interpolate_4_pixels_rgba32f(const QRgbaFloat32 t[], const QRgbaFloat32 b[], uint distx, uint disty)
+{
+ constexpr float f = 1.0f / 65536.0f;
+ const float dx = distx * f;
+ const float dy = disty * f;
+ const float idx = 1.0f - dx;
+ const float idy = 1.0f - dy;
+#ifdef __SSE2__
+ const __m128 vtl = _mm_load_ps((const float *)&t[0]);
+ const __m128 vtr = _mm_load_ps((const float *)&t[1]);
+ const __m128 vbl = _mm_load_ps((const float *)&b[0]);
+ const __m128 vbr = _mm_load_ps((const float *)&b[1]);
+
+ const __m128 vdx = _mm_set1_ps(dx);
+ const __m128 vidx = _mm_set1_ps(idx);
+ __m128 vt = interpolate_rgba32f(vtl, vidx, vtr, vdx);
+ __m128 vb = interpolate_rgba32f(vbl, vidx, vbr, vdx);
+ const __m128 vdy = _mm_set1_ps(dy);
+ const __m128 vidy = _mm_set1_ps(idy);
+ vt = interpolate_rgba32f(vt, vidy, vb, vdy);
+ QRgbaFloat32 res;
+ _mm_store_ps((float*)&res, vt);
+ return res;
+#else
+ QRgbaFloat32 xtop = interpolate_rgba32f(t[0], idx, t[1], dx);
+ QRgbaFloat32 xbot = interpolate_rgba32f(b[0], idx, b[1], dx);
+ xtop = interpolate_rgba32f(xtop, idy, xbot, dy);
+ return xtop;
+#endif
+}
+#endif // QT_CONFIG(raster_fp)
+
+static inline uint BYTE_MUL_RGB16(uint x, uint a) {
a += 1;
uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0;
t |= (((x & 0xf81f)*(a>>2)) >> 6) & 0xf81f;
return t;
}
-static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) {
+static inline uint BYTE_MUL_RGB16_32(uint x, uint a) {
uint t = (((x & 0xf81f07e0) >> 5)*a) & 0xf81f07e0;
t |= (((x & 0x07e0f81f)*a) >> 5) & 0x07e0f81f;
return t;
}
// qt_div_255 is a fast rounded division by 255 using an approximation that is accurate for all positive 16-bit integers
-static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
-static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_257_floor(uint x) { return (x - (x >> 8)) >> 8; }
-static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_257(uint x) { return qt_div_257_floor(x + 128); }
-static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; }
+static constexpr inline int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
+static constexpr inline uint qt_div_257_floor(uint x) { return (x - (x >> 8)) >> 8; }
+static constexpr inline uint qt_div_257(uint x) { return qt_div_257_floor(x + 128); }
+static constexpr inline uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; }
template <class T> inline void qt_memfill_template(T *dest, T color, qsizetype count)
{
@@ -1008,7 +1026,7 @@ inline uint comp_func_Plus_one_pixel(uint d, const uint s)
#undef AMIX
// must be multiple of 4 for easier SIMD implementations
-static Q_CONSTEXPR int BufferSize = 2048;
+static constexpr int BufferSize = 2048;
// A buffer of intermediate results used by simple bilinear scaling.
struct IntermediateBuffer
@@ -1023,70 +1041,6 @@ struct IntermediateBuffer
quint32 buffer_ag[BufferSize+2];
};
-template <QPixelLayout::BPP bpp>
-inline uint QT_FASTCALL qFetchPixel(const uchar *, int)
-{
- Q_UNREACHABLE();
- return 0;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
-{
- return (src[index >> 3] >> (index & 7)) & 1;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
-{
- return (src[index >> 3] >> (~index & 7)) & 1;
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
-{
- return src[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
-{
- return reinterpret_cast<const quint16 *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
-{
- return reinterpret_cast<const quint24 *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
-{
- return reinterpret_cast<const uint *>(src)[index];
-}
-
-template <>
-inline uint QT_FASTCALL qFetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
-{
- // We have to do the conversion in fetch to fit into a 32bit uint
- QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
- return c.toArgb32();
-}
-
-typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
-
-constexpr FetchPixelFunc qFetchPixelTable[QPixelLayout::BPPCount] = {
- nullptr, // BPPNone
- qFetchPixel<QPixelLayout::BPP1MSB>,
- qFetchPixel<QPixelLayout::BPP1LSB>,
- qFetchPixel<QPixelLayout::BPP8>,
- qFetchPixel<QPixelLayout::BPP16>,
- qFetchPixel<QPixelLayout::BPP24>,
- qFetchPixel<QPixelLayout::BPP32>,
- qFetchPixel<QPixelLayout::BPP64>,
-};
-
QT_END_NAMESPACE
#endif // QDRAWHELPER_P_H
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 77b5ab42c5..79590534f3 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qdrawhelper_x86_p.h>
@@ -233,7 +197,7 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u
}
}
-#ifndef __AVX2__
+#ifndef __haswell__
static Q_NEVER_INLINE
void Q_DECL_VECTORCALL qt_memfillXX_aligned(void *dest, __m128i value128, quintptr bytecount)
{
@@ -317,7 +281,7 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, qsizetype count)
qt_memfillXX_aligned(dest, _mm_set1_epi32(value), count * sizeof(quint32));
}
-#endif // !__AVX2__
+#endif // !__haswell__
void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha)
{
@@ -397,7 +361,7 @@ void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y,
0x04040404, 0x08080808);
const __m128i maskadd2 = _mm_set_epi32(0x7f7f7f7f, 0x7e7e7e7e,
0x7c7c7c7c, 0x78787878);
- while (height--) {
+ while (--height >= 0) {
for (int x = 0; x < width; x += 8) {
const quint8 s = src[x >> 3];
if (!s)
@@ -416,7 +380,7 @@ void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y,
src += stride;
}
} else {
- while (height--) {
+ while (--height >= 0) {
const quint8 s = *src;
if (s) {
__m128i mask1 = _mm_set1_epi8(s);
@@ -459,7 +423,7 @@ QT_WARNING_DISABLE_MSVC(4309) // truncation of constant value
const __m128i maskadd = _mm_set_epi16(0x7f7f, 0x7e7e, 0x7c7c, 0x7878,
0x7070, 0x6060, 0x4040, 0x0000);
- while (height--) {
+ while (--height >= 0) {
for (int x = 0; x < width; x += 8) {
const quint8 s = src[x >> 3];
if (!s)
@@ -533,66 +497,42 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
return qt_scale_image_argb32_on_argb32(destPixels, dbpl, srcPixels, sbpl, srch, targetRect, sourceRect, clip, const_alpha);
}
- qreal sx = targetRect.width() / (qreal) sourceRect.width();
- qreal sy = targetRect.height() / (qreal) sourceRect.height();
+ qreal sx = sourceRect.width() / (qreal)targetRect.width();
+ qreal sy = sourceRect.height() / (qreal)targetRect.height();
- int ix = 0x00010000 / sx;
- int iy = 0x00010000 / sy;
+ const int ix = 0x00010000 * sx;
+ const int iy = 0x00010000 * sy;
- int cx1 = clip.x();
- int cx2 = clip.x() + clip.width();
- int cy1 = clip.top();
- int cy2 = clip.y() + clip.height();
-
- int tx1 = qRound(targetRect.left());
- int tx2 = qRound(targetRect.right());
- int ty1 = qRound(targetRect.top());
- int ty2 = qRound(targetRect.bottom());
-
- if (tx2 < tx1)
- qSwap(tx2, tx1);
- if (ty2 < ty1)
- qSwap(ty2, ty1);
-
- if (tx1 < cx1)
- tx1 = cx1;
- if (tx2 >= cx2)
- tx2 = cx2;
-
- if (tx1 >= tx2)
+ QRect tr = targetRect.normalized().toRect();
+ tr = tr.intersected(clip);
+ if (tr.isEmpty())
return;
-
- if (ty1 < cy1)
- ty1 = cy1;
- if (ty2 >= cy2)
- ty2 = cy2;
- if (ty1 >= ty2)
- return;
-
- int h = ty2 - ty1;
- int w = tx2 - tx1;
+ const int tx1 = tr.left();
+ const int ty1 = tr.top();
+ int h = tr.height();
+ int w = tr.width();
quint32 basex;
quint32 srcy;
if (sx < 0) {
- int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
+ int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * sx * 65536) + 1;
basex = quint32(sourceRect.right() * 65536) + dstx;
} else {
- int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
+ int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * sx * 65536) - 1;
basex = quint32(sourceRect.left() * 65536) + dstx;
}
if (sy < 0) {
- int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
+ int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * sy * 65536) + 1;
srcy = quint32(sourceRect.bottom() * 65536) + dsty;
} else {
- int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
+ int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * sy * 65536) - 1;
srcy = quint32(sourceRect.top() * 65536) + dsty;
}
quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1;
- const __m128i nullVector = _mm_set1_epi32(0);
+ const __m128i nullVector = _mm_setzero_si128();
const __m128i half = _mm_set1_epi16(0x80);
const __m128i one = _mm_set1_epi16(0xff);
const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
@@ -618,7 +558,7 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(quint32)))
--w;
- while (h--) {
+ while (--h >= 0) {
const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
int srcx = basex;
int x = 0;
@@ -631,13 +571,14 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
__m128i srcxVector = _mm_set_epi32(srcx, srcx + ix, srcx + ix + ix, srcx + ix + ix + ix);
- for (; x<w - 3; x += 4) {
- union Vect_buffer { __m128i vect; quint32 i[4]; };
- Vect_buffer addr;
- addr.vect = _mm_srli_epi32(srcxVector, 16);
+ for (; x < (w - 3); x += 4) {
+ const int idx0 = _mm_extract_epi16(srcxVector, 1);
+ const int idx1 = _mm_extract_epi16(srcxVector, 3);
+ const int idx2 = _mm_extract_epi16(srcxVector, 5);
+ const int idx3 = _mm_extract_epi16(srcxVector, 7);
srcxVector = _mm_add_epi32(srcxVector, ixVector);
- const __m128i srcVector = _mm_set_epi32(src[addr.i[0]], src[addr.i[1]], src[addr.i[2]], src[addr.i[3]]);
+ const __m128i srcVector = _mm_set_epi32(src[idx0], src[idx1], src[idx2], src[idx3]);
BLEND_SOURCE_OVER_ARGB32_SSE2_helper(dst, srcVector, nullVector, half, one, colorMask, alphaMask);
}
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp
index 5b71d33043..a7b4e6ba76 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qdrawhelper_p.h>
#include <private/qdrawingprimitive_sse2_p.h>
@@ -46,7 +10,7 @@
QT_BEGIN_NAMESPACE
-#ifndef __AVX2__
+#ifndef __haswell__
template<bool RGBA>
static void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count)
{
@@ -142,7 +106,7 @@ static void convertARGBToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int cou
buffer[i] = QRgba64::fromArgb32(s).premultiplied();
}
}
-#endif // __AVX2__
+#endif // __haswell__
static inline __m128 Q_DECL_VECTORCALL reciprocal_mul_ps(__m128 a, float mul)
{
@@ -327,83 +291,167 @@ static inline void convertARGBFromRGBA64PM_sse4(uint *buffer, const QRgba64 *src
}
}
-#ifndef __AVX2__
-void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *)
+template<bool mask>
+static inline void convertRGBA64FromRGBA64PM_sse4(QRgba64 *buffer, const QRgba64 *src, int count)
+{
+ int i = 0;
+ if ((_MM_GET_EXCEPTION_MASK() & _MM_MASK_INVALID) == 0) {
+ for (; i < count; ++i) {
+ QRgba64 v = src[i].unpremultiplied();
+ if (mask)
+ v.setAlpha(65535);
+ buffer[i] = v;
+ }
+ return;
+ }
+ const __m128i alphaMask = _mm_set1_epi64x(qint64(Q_UINT64_C(0xffff) << 48));
+ const __m128i zero = _mm_setzero_si128();
+
+ for (; i < count - 3; i += 4) {
+ __m128i srcVector1 = _mm_loadu_si128((const __m128i *)&src[i + 0]);
+ __m128i srcVector2 = _mm_loadu_si128((const __m128i *)&src[i + 2]);
+ bool transparent1 = _mm_testz_si128(srcVector1, alphaMask);
+ bool opaque1 = _mm_testc_si128(srcVector1, alphaMask);
+ bool transparent2 = _mm_testz_si128(srcVector2, alphaMask);
+ bool opaque2 = _mm_testc_si128(srcVector2, alphaMask);
+
+ if (!(transparent1 && transparent2)) {
+ if (!(opaque1 && opaque2)) {
+ __m128i srcVector1Alpha = _mm_srli_epi64(srcVector1, 48);
+ __m128i srcVector2Alpha = _mm_srli_epi64(srcVector2, 48);
+ __m128i srcVectorAlpha = _mm_packus_epi32(srcVector1Alpha, srcVector2Alpha);
+ const __m128 a = _mm_cvtepi32_ps(srcVectorAlpha);
+ const __m128 ia = reciprocal_mul_ps(a, 65535.0f);
+ __m128i src1 = _mm_unpacklo_epi16(srcVector1, zero);
+ __m128i src2 = _mm_unpackhi_epi16(srcVector1, zero);
+ __m128i src3 = _mm_unpacklo_epi16(srcVector2, zero);
+ __m128i src4 = _mm_unpackhi_epi16(srcVector2, zero);
+ __m128 ia1 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(0, 0, 0, 0));
+ __m128 ia2 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(1, 1, 1, 1));
+ __m128 ia3 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(2, 2, 2, 2));
+ __m128 ia4 = _mm_shuffle_ps(ia, ia, _MM_SHUFFLE(3, 3, 3, 3));
+ src1 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src1), ia1));
+ src2 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src2), ia2));
+ src3 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src3), ia3));
+ src4 = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(src4), ia4));
+ src1 = _mm_packus_epi32(src1, src2);
+ src3 = _mm_packus_epi32(src3, src4);
+ // Handle potential alpha == 0 values:
+ __m128i srcVector1AlphaMask = _mm_cmpeq_epi64(srcVector1Alpha, zero);
+ __m128i srcVector2AlphaMask = _mm_cmpeq_epi64(srcVector2Alpha, zero);
+ src1 = _mm_andnot_si128(srcVector1AlphaMask, src1);
+ src3 = _mm_andnot_si128(srcVector2AlphaMask, src3);
+ // Fixup alpha values:
+ if (mask) {
+ src1 = _mm_or_si128(src1, alphaMask);
+ src3 = _mm_or_si128(src3, alphaMask);
+ } else {
+ src1 = _mm_blendv_epi8(src1, srcVector1, alphaMask);
+ src3 = _mm_blendv_epi8(src3, srcVector2, alphaMask);
+ }
+ _mm_storeu_si128((__m128i *)&buffer[i + 0], src1);
+ _mm_storeu_si128((__m128i *)&buffer[i + 2], src3);
+ } else {
+ if (mask) {
+ srcVector1 = _mm_or_si128(srcVector1, alphaMask);
+ srcVector2 = _mm_or_si128(srcVector2, alphaMask);
+ }
+ if (mask || src != buffer) {
+ _mm_storeu_si128((__m128i *)&buffer[i + 0], srcVector1);
+ _mm_storeu_si128((__m128i *)&buffer[i + 2], srcVector2);
+ }
+ }
+ } else {
+ _mm_storeu_si128((__m128i *)&buffer[i + 0], zero);
+ _mm_storeu_si128((__m128i *)&buffer[i + 2], zero);
+ }
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ QRgba64 v = src[i].unpremultiplied();
+ if (mask)
+ v.setAlpha(65535);
+ buffer[i] = v;
+ }
+}
+
+#ifndef __haswell__
+void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_sse4<false>(buffer, buffer, count);
}
-void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QVector<QRgb> *)
+void QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_sse4<true>(buffer, buffer, count);
}
const QRgba64 * QT_FASTCALL convertARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_sse4<false>(buffer, src, count);
return buffer;
}
const QRgba64 * QT_FASTCALL convertRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_sse4<true>(buffer, src, count);
return buffer;
}
const uint *QT_FASTCALL fetchARGB32ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_sse4<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM_sse4(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToARGB32PM_sse4<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_sse4<false>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
convertARGBToRGBA64PM_sse4<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
-#endif // __AVX2__
+#endif // __haswell__
void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_sse4<false,true>(d, src, count);
}
void QT_FASTCALL storeARGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_sse4<false,false>(d, src, count);
}
void QT_FASTCALL storeRGBA8888FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_sse4<true,false>(d, src, count);
}
void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
convertARGBFromARGB32PM_sse4<true,true>(d, src, count);
@@ -411,13 +459,20 @@ void QT_FASTCALL storeRGBXFromARGB32PM_sse4(uchar *dest, const uint *src, int in
template<QtPixelOrder PixelOrder>
void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
for (int i = 0; i < count; ++i)
d[i] = qConvertArgb32ToA2rgb30_sse4<PixelOrder>(src[i]);
}
+template
+void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *);
+template
+void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *);
+
#if QT_CONFIG(raster_64bit)
void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
{
@@ -433,25 +488,95 @@ void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, in
#endif
void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
convertARGBFromRGBA64PM_sse4<false>(d, src, count);
}
void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
convertARGBFromRGBA64PM_sse4<true>(d, src, count);
}
-template
-void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
-template
-void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderRGB>(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *);
+void QT_FASTCALL storeRGBA64FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = (QRgba64 *)dest + index;
+ convertRGBA64FromRGBA64PM_sse4<false>(d, src, count);
+}
+
+void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = (QRgba64 *)dest + index;
+ convertRGBA64FromRGBA64PM_sse4<true>(d, src, count);
+}
+
+#if QT_CONFIG(raster_fp)
+const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F_sse4(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ vsf = _mm_mul_ps(vsf, vsa);
+ vsf = _mm_insert_ps(vsf, vsa, 0x30);
+ _mm_store_ps(reinterpret_cast<float *>(buffer + i), vsf);
+ }
+ return buffer;
+}
+
+void QT_FASTCALL storeRGBX32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ const __m128 zero = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(src + i));
+ const __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsf = _mm_mul_ps(vsf, vsr);
+ vsf = _mm_insert_ps(vsf, _mm_set_ss(1.0f), 0x30);
+ }
+ _mm_store_ps(reinterpret_cast<float *>(d + i), vsf);
+ }
+}
+
+void QT_FASTCALL storeRGBA32FFromRGBA32F_sse4(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ const __m128 zero = _mm_set1_ps(0.0f);
+ for (int i = 0; i < count; ++i) {
+ __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(src + i));
+ const __m128 vsa = _mm_shuffle_ps(vsf, vsf, _MM_SHUFFLE(3, 3, 3, 3));
+ const float a = _mm_cvtss_f32(vsa);
+ if (a == 1.0f)
+ { }
+ else if (a == 0.0f)
+ vsf = zero;
+ else {
+ __m128 vsr = _mm_rcp_ps(vsa);
+ vsr = _mm_sub_ps(_mm_add_ps(vsr, vsr), _mm_mul_ps(vsr, _mm_mul_ps(vsr, vsa)));
+ vsr = _mm_insert_ps(vsr, _mm_set_ss(1.0f), 0x30);
+ vsf = _mm_mul_ps(vsf, vsr);
+ }
+ _mm_store_ps(reinterpret_cast<float *>(d + i), vsf);
+ }
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp
index a175b591dd..6e905c7f84 100644
--- a/src/gui/painting/qdrawhelper_ssse3.cpp
+++ b/src/gui/painting/qdrawhelper_ssse3.cpp
@@ -1,42 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qdrawhelper_x86_p.h>
@@ -47,7 +11,7 @@
QT_BEGIN_NAMESPACE
/* The instruction palignr uses direct arguments, so we have to generate the code fo the different
- shift (4, 8, 12). Checking the alignment inside the loop is unfortunatelly way too slow.
+ shift (4, 8, 12). Checking the alignment inside the loop is unfortunately way too slow.
*/
#define BLENDING_LOOP(palignrOffset, length)\
for (; x-minusOffsetToAlignSrcOn16Bytes < length-7; x += 4) { \
diff --git a/src/gui/painting/qdrawhelper_x86_p.h b/src/gui/painting/qdrawhelper_x86_p.h
index 869abcc637..15773fe014 100644
--- a/src/gui/painting/qdrawhelper_x86_p.h
+++ b/src/gui/painting/qdrawhelper_x86_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDRAWHELPER_X86_P_H
#define QDRAWHELPER_X86_P_H
diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h
index cc8d230fa8..2233b73e56 100644
--- a/src/gui/painting/qdrawingprimitive_sse2_p.h
+++ b/src/gui/painting/qdrawingprimitive_sse2_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDRAWINGPRIMITIVE_SSE2_P_H
#define QDRAWINGPRIMITIVE_SSE2_P_H
@@ -64,7 +28,7 @@ QT_BEGIN_NAMESPACE
* Multiply the components of pixelVector by alphaChannel
* Each 32bits components of alphaChannel must be in the form 0x00AA00AA
* colorMask must have 0x00ff00ff on each 32 bits component
- * half must have the value 128 (0x80) for each 32 bits compnent
+ * half must have the value 128 (0x80) for each 32 bits component
*/
#define BYTE_MUL_SSE2(result, pixelVector, alphaChannel, colorMask, half) \
{ \
@@ -102,7 +66,7 @@ QT_BEGIN_NAMESPACE
* Each 32bits components of alphaChannel must be in the form 0x00AA00AA
* oneMinusAlphaChannel must be 255 - alpha for each 32 bits component
* colorMask must have 0x00ff00ff on each 32 bits component
- * half must have the value 128 (0x80) for each 32 bits compnent
+ * half must have the value 128 (0x80) for each 32 bits component
*/
#define INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, alphaChannel, oneMinusAlphaChannel, colorMask, half) { \
/* interpolate AG */\
@@ -232,7 +196,7 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
#if QT_COMPILER_SUPPORTS_HERE(SSE4_1)
QT_FUNCTION_TARGET(SSE2)
-Q_ALWAYS_INLINE void Q_DECL_VECTORCALL reciprocal_mul_ss(__m128 &ia, const __m128 a, float mul)
+static inline void Q_DECL_VECTORCALL reciprocal_mul_ss(__m128 &ia, const __m128 a, float mul)
{
ia = _mm_rcp_ss(a); // Approximate 1/a
// Improve precision of ia using Newton-Raphson
@@ -242,7 +206,7 @@ Q_ALWAYS_INLINE void Q_DECL_VECTORCALL reciprocal_mul_ss(__m128 &ia, const __m12
}
QT_FUNCTION_TARGET(SSE4_1)
-inline QRgb qUnpremultiply_sse4(QRgb p)
+static inline QRgb qUnpremultiply_sse4(QRgb p)
{
const uint alpha = qAlpha(p);
if (alpha == 255)
@@ -262,14 +226,14 @@ inline QRgb qUnpremultiply_sse4(QRgb p)
template<enum QtPixelOrder PixelOrder>
QT_FUNCTION_TARGET(SSE4_1)
-inline uint qConvertArgb32ToA2rgb30_sse4(QRgb p)
+static inline uint qConvertArgb32ToA2rgb30_sse4(QRgb p)
{
const uint alpha = qAlpha(p);
if (alpha == 255)
return qConvertRgb32ToRgb30<PixelOrder>(p);
if (alpha == 0)
return 0;
- Q_CONSTEXPR float mult = 1023.0f / (255 >> 6);
+ constexpr float mult = 1023.0f / (255 >> 6);
const uint newalpha = (alpha >> 6);
const __m128 va = _mm_set1_ps(alpha);
__m128 via;
@@ -292,7 +256,7 @@ inline uint qConvertArgb32ToA2rgb30_sse4(QRgb p)
template<enum QtPixelOrder PixelOrder>
QT_FUNCTION_TARGET(SSE4_1)
-inline uint qConvertRgba64ToRgb32_sse4(QRgba64 p)
+static inline uint qConvertRgba64ToRgb32_sse4(QRgba64 p)
{
if (p.isTransparent())
return 0;
diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp
index 7cd700a84a..8e871238cc 100644
--- a/src/gui/painting/qemulationpaintengine.cpp
+++ b/src/gui/painting/qemulationpaintengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qemulationpaintengine_p.h>
#include <private/qpainter_p.h>
@@ -103,8 +67,8 @@ void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
return;
}
} else if (style == Qt::TexturePattern) {
- qreal dpr = qHasPixmapTexture(brush) ? brush.texture().devicePixelRatioF() : brush.textureImage().devicePixelRatioF();
- if (!qFuzzyCompare(dpr, 1.0)) {
+ qreal dpr = qHasPixmapTexture(brush) ? brush.texture().devicePixelRatio() : brush.textureImage().devicePixelRatio();
+ if (!qFuzzyCompare(dpr, qreal(1.0))) {
QBrush copy = brush;
combineXForm(&copy, QRectF(0, 0, 1.0/dpr, 1.0/dpr));
real_engine->fill(path, copy);
diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h
index a2eb9b008c..cabb8485cb 100644
--- a/src/gui/painting/qemulationpaintengine_p.h
+++ b/src/gui/painting/qemulationpaintengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEMULATIONPAINTENGINE_P_H
#define QEMULATIONPAINTENGINE_P_H
diff --git a/src/gui/painting/qfixed_p.h b/src/gui/painting/qfixed_p.h
index 846592881c..c0a13d057f 100644
--- a/src/gui/painting/qfixed_p.h
+++ b/src/gui/painting/qfixed_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFIXED_P_H
#define QFIXED_P_H
@@ -54,58 +18,63 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qdebug.h"
#include "QtCore/qpoint.h"
+#include "QtCore/qnumeric.h"
#include "QtCore/qsize.h"
QT_BEGIN_NAMESPACE
struct QFixed {
private:
- Q_DECL_CONSTEXPR QFixed(int val, int) : val(val) {} // 2nd int is just a dummy for disambiguation
+ constexpr QFixed(int val, int) : val(val) {} // 2nd int is just a dummy for disambiguation
public:
- Q_DECL_CONSTEXPR QFixed() : val(0) {}
- Q_DECL_CONSTEXPR QFixed(int i) : val(i * 64) {}
- Q_DECL_CONSTEXPR QFixed(long i) : val(i * 64) {}
- QFixed &operator=(int i) { val = i * 64; return *this; }
- QFixed &operator=(long i) { val = i * 64; return *this; }
+ constexpr QFixed() : val(0) {}
+ constexpr QFixed(int i) : val(i * 64) {}
+ constexpr QFixed(long i) : val(i * 64) {}
+ constexpr QFixed(long long i) : val(i * 64) {}
- Q_DECL_CONSTEXPR static QFixed fromReal(qreal r) { return fromFixed((int)(r*qreal(64))); }
- Q_DECL_CONSTEXPR static QFixed fromFixed(int fixed) { return QFixed(fixed,0); } // uses private ctor
+ constexpr static QFixed fromReal(qreal r) { return fromFixed((int)(r*qreal(64))); }
+ constexpr static QFixed fromFixed(int fixed) { return QFixed(fixed,0); } // uses private ctor
- Q_DECL_CONSTEXPR inline int value() const { return val; }
+ constexpr inline int value() const { return val; }
inline void setValue(int value) { val = value; }
- Q_DECL_CONSTEXPR inline int toInt() const { return (((val)+32) & -64)>>6; }
- Q_DECL_CONSTEXPR inline qreal toReal() const { return ((qreal)val)/(qreal)64; }
+ constexpr inline int toInt() const { return (((val)+32) & -64)>>6; }
+ constexpr inline qreal toReal() const { return ((qreal)val)/(qreal)64; }
- Q_DECL_CONSTEXPR inline int truncate() const { return val>>6; }
- Q_DECL_CONSTEXPR inline QFixed round() const { return fromFixed(((val)+32) & -64); }
- Q_DECL_CONSTEXPR inline QFixed floor() const { return fromFixed((val) & -64); }
- Q_DECL_CONSTEXPR inline QFixed ceil() const { return fromFixed((val+63) & -64); }
+ constexpr inline int truncate() const { return val>>6; }
+ constexpr inline QFixed round() const { return fromFixed(((val)+32) & -64); }
+ constexpr inline QFixed floor() const { return fromFixed((val) & -64); }
+ constexpr inline QFixed ceil() const { return fromFixed((val+63) & -64); }
- Q_DECL_CONSTEXPR inline QFixed operator+(int i) const { return fromFixed(val + i * 64); }
- Q_DECL_CONSTEXPR inline QFixed operator+(uint i) const { return fromFixed((val + (i<<6))); }
- Q_DECL_CONSTEXPR inline QFixed operator+(const QFixed &other) const { return fromFixed((val + other.val)); }
+ constexpr inline QFixed operator+(int i) const { return fromFixed(val + i * 64); }
+ constexpr inline QFixed operator+(uint i) const { return fromFixed((val + (i<<6))); }
+ constexpr inline QFixed operator+(QFixed other) const { return fromFixed((val + other.val)); }
inline QFixed &operator+=(int i) { val += i * 64; return *this; }
inline QFixed &operator+=(uint i) { val += (i<<6); return *this; }
- inline QFixed &operator+=(const QFixed &other) { val += other.val; return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator-(int i) const { return fromFixed(val - i * 64); }
- Q_DECL_CONSTEXPR inline QFixed operator-(uint i) const { return fromFixed((val - (i<<6))); }
- Q_DECL_CONSTEXPR inline QFixed operator-(const QFixed &other) const { return fromFixed((val - other.val)); }
+ inline QFixed &operator+=(QFixed other) { val += other.val; return *this; }
+ constexpr inline QFixed operator-(int i) const { return fromFixed(val - i * 64); }
+ constexpr inline QFixed operator-(uint i) const { return fromFixed((val - (i<<6))); }
+ constexpr inline QFixed operator-(QFixed other) const { return fromFixed((val - other.val)); }
inline QFixed &operator-=(int i) { val -= i * 64; return *this; }
inline QFixed &operator-=(uint i) { val -= (i<<6); return *this; }
- inline QFixed &operator-=(const QFixed &other) { val -= other.val; return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator-() const { return fromFixed(-val); }
-
- Q_DECL_CONSTEXPR inline bool operator==(const QFixed &other) const { return val == other.val; }
- Q_DECL_CONSTEXPR inline bool operator!=(const QFixed &other) const { return val != other.val; }
- Q_DECL_CONSTEXPR inline bool operator<(const QFixed &other) const { return val < other.val; }
- Q_DECL_CONSTEXPR inline bool operator>(const QFixed &other) const { return val > other.val; }
- Q_DECL_CONSTEXPR inline bool operator<=(const QFixed &other) const { return val <= other.val; }
- Q_DECL_CONSTEXPR inline bool operator>=(const QFixed &other) const { return val >= other.val; }
- Q_DECL_CONSTEXPR inline bool operator!() const { return !val; }
+ inline QFixed &operator-=(QFixed other) { val -= other.val; return *this; }
+ constexpr inline QFixed operator-() const { return fromFixed(-val); }
+
+#define REL_OP(op) \
+ friend constexpr bool operator op(QFixed lhs, QFixed rhs) noexcept \
+ { return lhs.val op rhs.val; }
+ REL_OP(==)
+ REL_OP(!=)
+ REL_OP(< )
+ REL_OP(> )
+ REL_OP(<=)
+ REL_OP(>=)
+#undef REL_OP
+
+ constexpr inline bool operator!() const { return !val; }
inline QFixed &operator/=(int x) { val /= x; return *this; }
- inline QFixed &operator/=(const QFixed &o) {
+ inline QFixed &operator/=(QFixed o) {
if (o.val == 0) {
val = 0x7FFFFFFFL;
} else {
@@ -121,12 +90,12 @@ public:
}
return *this;
}
- Q_DECL_CONSTEXPR inline QFixed operator/(int d) const { return fromFixed(val/d); }
+ constexpr inline QFixed operator/(int d) const { return fromFixed(val/d); }
inline QFixed operator/(QFixed b) const { QFixed f = *this; return (f /= b); }
inline QFixed operator>>(int d) const { QFixed f = *this; f.val >>= d; return f; }
inline QFixed &operator*=(int i) { val *= i; return *this; }
inline QFixed &operator*=(uint i) { val *= i; return *this; }
- inline QFixed &operator*=(const QFixed &o) {
+ inline QFixed &operator*=(QFixed o) {
bool neg = false;
qint64 a = val;
qint64 b = o.val;
@@ -137,80 +106,86 @@ public:
val = neg ? -res : res;
return *this;
}
- Q_DECL_CONSTEXPR inline QFixed operator*(int i) const { return fromFixed(val * i); }
- Q_DECL_CONSTEXPR inline QFixed operator*(uint i) const { return fromFixed(val * i); }
- inline QFixed operator*(const QFixed &o) const { QFixed f = *this; return (f *= o); }
+ constexpr inline QFixed operator*(int i) const { return fromFixed(val * i); }
+ constexpr inline QFixed operator*(uint i) const { return fromFixed(val * i); }
+ inline QFixed operator*(QFixed o) const { QFixed f = *this; return (f *= o); }
private:
- Q_DECL_CONSTEXPR QFixed(qreal i) : val((int)(i*qreal(64))) {}
- QFixed &operator=(qreal i) { val = (int)(i*qreal(64)); return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator+(qreal i) const { return fromFixed((val + (int)(i*qreal(64)))); }
+ constexpr QFixed(qreal i) : val((int)(i*qreal(64))) {}
+ constexpr inline QFixed operator+(qreal i) const { return fromFixed((val + (int)(i*qreal(64)))); }
inline QFixed &operator+=(qreal i) { val += (int)(i*64); return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator-(qreal i) const { return fromFixed((val - (int)(i*qreal(64)))); }
+ constexpr inline QFixed operator-(qreal i) const { return fromFixed((val - (int)(i*qreal(64)))); }
inline QFixed &operator-=(qreal i) { val -= (int)(i*64); return *this; }
inline QFixed &operator/=(qreal r) { val = (int)(val/r); return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator/(qreal d) const { return fromFixed((int)(val/d)); }
+ constexpr inline QFixed operator/(qreal d) const { return fromFixed((int)(val/d)); }
inline QFixed &operator*=(qreal d) { val = (int) (val*d); return *this; }
- Q_DECL_CONSTEXPR inline QFixed operator*(qreal d) const { return fromFixed((int) (val*d)); }
+ constexpr inline QFixed operator*(qreal d) const { return fromFixed((int) (val*d)); }
int val;
};
Q_DECLARE_TYPEINFO(QFixed, Q_PRIMITIVE_TYPE);
#define QFIXED_MAX (INT_MAX/256)
-Q_DECL_CONSTEXPR inline int qRound(const QFixed &f) { return f.toInt(); }
-Q_DECL_CONSTEXPR inline int qFloor(const QFixed &f) { return f.floor().truncate(); }
-
-Q_DECL_CONSTEXPR inline QFixed operator*(int i, const QFixed &d) { return d*i; }
-Q_DECL_CONSTEXPR inline QFixed operator+(int i, const QFixed &d) { return d+i; }
-Q_DECL_CONSTEXPR inline QFixed operator-(int i, const QFixed &d) { return -(d-i); }
-Q_DECL_CONSTEXPR inline QFixed operator*(uint i, const QFixed &d) { return d*i; }
-Q_DECL_CONSTEXPR inline QFixed operator+(uint i, const QFixed &d) { return d+i; }
-Q_DECL_CONSTEXPR inline QFixed operator-(uint i, const QFixed &d) { return -(d-i); }
-// Q_DECL_CONSTEXPR inline QFixed operator*(qreal d, const QFixed &d2) { return d2*d; }
-
-Q_DECL_CONSTEXPR inline bool operator==(const QFixed &f, int i) { return f.value() == i * 64; }
-Q_DECL_CONSTEXPR inline bool operator==(int i, const QFixed &f) { return f.value() == i * 64; }
-Q_DECL_CONSTEXPR inline bool operator!=(const QFixed &f, int i) { return f.value() != i * 64; }
-Q_DECL_CONSTEXPR inline bool operator!=(int i, const QFixed &f) { return f.value() != i * 64; }
-Q_DECL_CONSTEXPR inline bool operator<=(const QFixed &f, int i) { return f.value() <= i * 64; }
-Q_DECL_CONSTEXPR inline bool operator<=(int i, const QFixed &f) { return i * 64 <= f.value(); }
-Q_DECL_CONSTEXPR inline bool operator>=(const QFixed &f, int i) { return f.value() >= i * 64; }
-Q_DECL_CONSTEXPR inline bool operator>=(int i, const QFixed &f) { return i * 64 >= f.value(); }
-Q_DECL_CONSTEXPR inline bool operator<(const QFixed &f, int i) { return f.value() < i * 64; }
-Q_DECL_CONSTEXPR inline bool operator<(int i, const QFixed &f) { return i * 64 < f.value(); }
-Q_DECL_CONSTEXPR inline bool operator>(const QFixed &f, int i) { return f.value() > i * 64; }
-Q_DECL_CONSTEXPR inline bool operator>(int i, const QFixed &f) { return i * 64 > f.value(); }
+constexpr inline int qRound(QFixed f) { return f.toInt(); }
+constexpr inline int qFloor(QFixed f) { return f.floor().truncate(); }
+
+constexpr inline QFixed operator*(int i, QFixed d) { return d*i; }
+constexpr inline QFixed operator+(int i, QFixed d) { return d+i; }
+constexpr inline QFixed operator-(int i, QFixed d) { return -(d-i); }
+constexpr inline QFixed operator*(uint i, QFixed d) { return d*i; }
+constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; }
+constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); }
+// constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; }
+
+inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r)
+{
+ int val;
+ bool result = qAddOverflow(v1.value(), v2.value(), &val);
+ r->setValue(val);
+ return result;
+}
+
+inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r)
+{
+ int val;
+ bool result = qMulOverflow(v1.value(), v2.value(), &val);
+ r->setValue(val);
+ return result;
+}
#ifndef QT_NO_DEBUG_STREAM
-inline QDebug &operator<<(QDebug &dbg, const QFixed &f)
+inline QDebug &operator<<(QDebug &dbg, QFixed f)
{ return dbg << f.toReal(); }
#endif
struct QFixedPoint {
QFixed x;
QFixed y;
- Q_DECL_CONSTEXPR inline QFixedPoint() {}
- Q_DECL_CONSTEXPR inline QFixedPoint(const QFixed &_x, const QFixed &_y) : x(_x), y(_y) {}
- Q_DECL_CONSTEXPR QPointF toPointF() const { return QPointF(x.toReal(), y.toReal()); }
- Q_DECL_CONSTEXPR static QFixedPoint fromPointF(const QPointF &p) {
+ constexpr inline QFixedPoint() {}
+ constexpr inline QFixedPoint(QFixed _x, QFixed _y) : x(_x), y(_y) {}
+ constexpr QPointF toPointF() const { return QPointF(x.toReal(), y.toReal()); }
+ constexpr static QFixedPoint fromPointF(const QPointF &p) {
return QFixedPoint(QFixed::fromReal(p.x()), QFixed::fromReal(p.y()));
}
+ constexpr inline bool operator==(const QFixedPoint &other) const
+ {
+ return x == other.x && y == other.y;
+ }
};
Q_DECLARE_TYPEINFO(QFixedPoint, Q_PRIMITIVE_TYPE);
-Q_DECL_CONSTEXPR inline QFixedPoint operator-(const QFixedPoint &p1, const QFixedPoint &p2)
+constexpr inline QFixedPoint operator-(const QFixedPoint &p1, const QFixedPoint &p2)
{ return QFixedPoint(p1.x - p2.x, p1.y - p2.y); }
-Q_DECL_CONSTEXPR inline QFixedPoint operator+(const QFixedPoint &p1, const QFixedPoint &p2)
+constexpr inline QFixedPoint operator+(const QFixedPoint &p1, const QFixedPoint &p2)
{ return QFixedPoint(p1.x + p2.x, p1.y + p2.y); }
struct QFixedSize {
QFixed width;
QFixed height;
- Q_DECL_CONSTEXPR QFixedSize() {}
- Q_DECL_CONSTEXPR QFixedSize(QFixed _width, QFixed _height) : width(_width), height(_height) {}
- Q_DECL_CONSTEXPR QSizeF toSizeF() const { return QSizeF(width.toReal(), height.toReal()); }
- Q_DECL_CONSTEXPR static QFixedSize fromSizeF(const QSizeF &s) {
+ constexpr QFixedSize() {}
+ constexpr QFixedSize(QFixed _width, QFixed _height) : width(_width), height(_height) {}
+ constexpr QSizeF toSizeF() const { return QSizeF(width.toReal(), height.toReal()); }
+ constexpr static QFixedSize fromSizeF(const QSizeF &s) {
return QFixedSize(QFixed::fromReal(s.width()), QFixed::fromReal(s.height()));
}
};
diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c
index 0143e9b602..3c222c49e1 100644
--- a/src/gui/painting/qgrayraster.c
+++ b/src/gui/painting/qgrayraster.c
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/***************************************************************************/
/* */
@@ -187,6 +151,7 @@ typedef ptrdiff_t QT_FT_PtrDist;
#include <stdlib.h>
#include <stdio.h>
+#include <assert.h>
#define QT_FT_UNUSED( x ) (void) x
@@ -216,11 +181,8 @@ typedef ptrdiff_t QT_FT_PtrDist;
#define PIXEL_BITS 8
#define ONE_PIXEL ( 1L << PIXEL_BITS )
-#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
-#define SUBPIXELS( x ) ( (TPos)(x) * ONE_PIXEL )
-#define FLOOR( x ) ( (x) & -ONE_PIXEL )
-#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
-#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
+#define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS )
+#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) )
#if PIXEL_BITS >= 6
#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
@@ -548,17 +510,13 @@ QT_FT_END_STMNT
TPos x2,
TCoord y2 )
{
- TCoord ex1, ex2, fx1, fx2, delta, mod;
- int p, first, dx;
+ TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod;
+ TPos p, dx;
int incr;
- dx = x2 - x1;
-
ex1 = TRUNC( x1 );
ex2 = TRUNC( x2 );
- fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
- fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
/* trivial case. Happens often */
if ( y1 == y2 )
@@ -567,26 +525,27 @@ QT_FT_END_STMNT
return;
}
+ fx1 = FRACT( x1 );
+ fx2 = FRACT( x2 );
+
/* everything is located in a single cell. That is easy! */
/* */
if ( ex1 == ex2 )
- {
- delta = y2 - y1;
- ras.area += (TArea)( fx1 + fx2 ) * delta;
- ras.cover += delta;
- return;
- }
+ goto End;
/* ok, we'll have to render a run of adjacent cells on the same */
/* scanline... */
/* */
- p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
- first = ONE_PIXEL;
- incr = 1;
+ dx = x2 - x1;
+ dy = y2 - y1;
- if ( dx < 0 )
+ if ( dx > 0 )
{
- p = fx1 * ( y2 - y1 );
+ p = ( ONE_PIXEL - fx1 ) * dy;
+ first = ONE_PIXEL;
+ incr = 1;
+ } else {
+ p = fx1 * dy;
first = 0;
incr = -1;
dx = -dx;
@@ -596,42 +555,42 @@ QT_FT_END_STMNT
ras.area += (TArea)( fx1 + first ) * delta;
ras.cover += delta;
-
- ex1 += incr;
+ y1 += delta;
+ ex1 += incr;
gray_set_cell( RAS_VAR_ ex1, ey );
- y1 += delta;
if ( ex1 != ex2 )
{
TCoord lift, rem;
- p = ONE_PIXEL * ( y2 - y1 + delta );
+ p = ONE_PIXEL * dy;
QT_FT_DIV_MOD( TCoord, p, dx, lift, rem );
- mod -= (int)dx;
-
- while ( ex1 != ex2 )
+ do
{
delta = lift;
mod += rem;
- if ( mod >= 0 )
+ if ( mod >= (TCoord)dx )
{
mod -= (TCoord)dx;
delta++;
}
- ras.area += (TArea)ONE_PIXEL * delta;
+ ras.area += (TArea)( ONE_PIXEL * delta );
ras.cover += delta;
y1 += delta;
ex1 += incr;
gray_set_cell( RAS_VAR_ ex1, ey );
- }
+ } while ( ex1 != ex2 );
}
+ fx1 = ONE_PIXEL - first;
- delta = y2 - y1;
- ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
- ras.cover += delta;
+ End:
+ dy = y2 - y1;
+
+ ras.area += (TArea)( ( fx1 + fx2 ) * dy );
+ ras.cover += dy;
}
@@ -643,25 +602,21 @@ QT_FT_END_STMNT
gray_render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
- TCoord ey1, ey2, fy1, fy2, mod;
- TPos dx, dy, x, x2;
- int p, first;
- int delta, rem, lift, incr;
-
+ TCoord ey1, ey2, fy1, fy2, first, delta, mod;
+ TPos p, dx, dy, x, x2;
+ int incr;
ey1 = TRUNC( ras.y );
ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
- fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
- fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
-
- dx = to_x - ras.x;
- dy = to_y - ras.y;
/* perform vertical clipping */
if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
goto End;
+ fy1 = FRACT( ras.y );
+ fy2 = FRACT( to_y );
+
/* everything is on a single scanline */
if ( ey1 == ey2 )
{
@@ -669,23 +624,31 @@ QT_FT_END_STMNT
goto End;
}
+ dx = to_x - ras.x;
+ dy = to_y - ras.y;
+
/* vertical line - avoid calling gray_render_scanline */
if ( dx == 0 )
{
TCoord ex = TRUNC( ras.x );
- TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
+ TCoord two_fx = FRACT( ras.x ) << 1;
TPos area, max_ey1;
- first = ONE_PIXEL;
- if ( dy < 0 )
+ if ( dy > 0)
+ {
+ first = ONE_PIXEL;
+ }
+ else
+ {
first = 0;
+ }
- delta = (int)( first - fy1 );
+ delta = first - fy1;
ras.area += (TArea)two_fx * delta;
ras.cover += delta;
- delta = (int)( first + first - ONE_PIXEL );
+ delta = first + first - ONE_PIXEL;
area = (TArea)two_fx * delta;
max_ey1 = ras.count_ey + ras.min_ey;
if (dy < 0) {
@@ -738,11 +701,13 @@ QT_FT_END_STMNT
}
/* ok, we have to render several scanlines */
- p = ( ONE_PIXEL - fy1 ) * dx;
- first = ONE_PIXEL;
- incr = 1;
-
- if ( dy < 0 )
+ if ( dy > 0)
+ {
+ p = ( ONE_PIXEL - fy1 ) * dx;
+ first = ONE_PIXEL;
+ incr = 1;
+ }
+ else
{
p = fy1 * dx;
first = 0;
@@ -750,13 +715,9 @@ QT_FT_END_STMNT
dy = -dy;
}
- delta = (int)( p / dy );
- mod = (int)( p % dy );
- if ( mod < 0 )
- {
- delta--;
- mod += (TCoord)dy;
- }
+ /* the fractional part of x-delta is mod/dy. It is essential to */
+ /* keep track of its accumulation for accurate rendering. */
+ QT_FT_DIV_MOD( TCoord, p, dy, delta, mod );
x = ras.x + delta;
gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
@@ -766,34 +727,36 @@ QT_FT_END_STMNT
if ( ey1 != ey2 )
{
- p = ONE_PIXEL * dx;
- QT_FT_DIV_MOD( int, p, dy, lift, rem );
- mod -= (int)dy;
+ TCoord lift, rem;
- while ( ey1 != ey2 )
+
+ p = ONE_PIXEL * dx;
+ QT_FT_DIV_MOD( TCoord, p, dy, lift, rem );
+
+ do
{
delta = lift;
mod += rem;
- if ( mod >= 0 )
+ if ( mod >= (TCoord)dy )
{
- mod -= (int)dy;
+ mod -= (TCoord)dy;
delta++;
}
x2 = x + delta;
- gray_render_scanline( RAS_VAR_ ey1, x,
- (TCoord)( ONE_PIXEL - first ), x2,
- (TCoord)first );
+ gray_render_scanline( RAS_VAR_ ey1,
+ x, ONE_PIXEL - first,
+ x2, first );
x = x2;
ey1 += incr;
gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
- }
+ } while ( ey1 != ey2 );
}
- gray_render_scanline( RAS_VAR_ ey1, x,
- (TCoord)( ONE_PIXEL - first ), to_x,
- fy2 );
+ gray_render_scanline( RAS_VAR_ ey1,
+ x, ONE_PIXEL - first,
+ to_x, fy2 );
End:
ras.x = to_x;
@@ -828,8 +791,8 @@ QT_FT_END_STMNT
dx = to_x - ras.x;
dy = to_y - ras.y;
- fx1 = ras.x - SUBPIXELS( ex1 );
- fy1 = ras.y - SUBPIXELS( ey1 );
+ fx1 = FRACT( ras.x );
+ fy1 = FRACT( ras.y );
if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
;
@@ -926,8 +889,8 @@ QT_FT_END_STMNT
} while ( ex1 != ex2 || ey1 != ey2 );
}
- fx2 = to_x - SUBPIXELS( ex2 );
- fy2 = to_y - SUBPIXELS( ey2 );
+ fx2 = FRACT( to_x );
+ fy2 = FRACT( to_y );
ras.cover += ( fy2 - fy1 );
ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
@@ -1103,7 +1066,7 @@ QT_FT_END_STMNT
L = QT_FT_HYPOT( dx_, dy_ );
/* Avoid possible arithmetic overflow below by splitting. */
- if ( L > 32767 )
+ if ( L >= (1 << 23) )
goto Split;
/* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
@@ -1253,13 +1216,13 @@ QT_FT_END_STMNT
y += (TCoord)ras.min_ey;
x += (TCoord)ras.min_ex;
- /* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
- if ( x >= 32767 )
- x = 32767;
+ /* QT_FT_Span.x is an int, so limit our coordinates appropriately */
+ if ( x >= (1 << 23) )
+ x = (1 << 23) - 1;
- /* QT_FT_Span.y is a 16-bit short, so limit our coordinates appropriately */
- if ( y >= 32767 )
- y = 32767;
+ /* QT_FT_Span.y is an int, so limit our coordinates appropriately */
+ if ( y >= (1 << 23) )
+ y = (1 << 23) - 1;
if ( coverage )
{
@@ -1273,10 +1236,10 @@ QT_FT_END_STMNT
span = ras.gray_spans + count - 1;
if ( count > 0 &&
span->y == y &&
- (int)span->x + span->len == (int)x &&
+ span->x + span->len == x &&
span->coverage == coverage )
{
- span->len = (unsigned short)( span->len + acount );
+ span->len = span->len + acount;
return;
}
@@ -1319,9 +1282,9 @@ QT_FT_END_STMNT
span++;
/* add a gray span to the current list */
- span->x = (short)x;
- span->len = (unsigned short)acount;
- span->y = (short)y;
+ span->x = x;
+ span->len = acount;
+ span->y = y;
span->coverage = (unsigned char)coverage;
ras.num_gray_spans++;
@@ -1839,8 +1802,11 @@ QT_FT_END_STMNT
if ( !raster || !raster->buffer || !raster->buffer_size )
return ErrRaster_Invalid_Argument;
- if ( raster->worker )
- raster->worker->skip_spans = params->skip_spans;
+ /* Should always be non-null, it is set by raster_reset() which is always */
+ /* called with a non-null pool, and a pool_size >= MINIMUM_POOL_SIZE. */
+ assert(raster->worker);
+
+ raster->worker->skip_spans = params->skip_spans;
/* If raster object and raster buffer are allocated, but */
/* raster size isn't of the minimum size, indicate out of */
@@ -1897,10 +1863,10 @@ QT_FT_END_STMNT
}
else
{
- ras.clip_box.xMin = -32768L;
- ras.clip_box.yMin = -32768L;
- ras.clip_box.xMax = 32767L;
- ras.clip_box.yMax = 32767L;
+ ras.clip_box.xMin = -(1 << 23);
+ ras.clip_box.yMin = -(1 << 23);
+ ras.clip_box.xMax = (1 << 23) - 1;
+ ras.clip_box.yMax = (1 << 23) - 1;
}
gray_init_cells( worker, raster->buffer, raster->buffer_size );
diff --git a/src/gui/painting/qgrayraster_p.h b/src/gui/painting/qgrayraster_p.h
index 86d54d4379..f9aae18e9d 100644
--- a/src/gui/painting/qgrayraster_p.h
+++ b/src/gui/painting/qgrayraster_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/***************************************************************************/
/* */
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index ea18f38c66..c01fa433ea 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -1,56 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qicc_p.h"
#include <qbuffer.h>
#include <qbytearray.h>
+#include <qvarlengtharray.h>
+#include <qhash.h>
#include <qdatastream.h>
#include <qendian.h>
#include <qloggingcategory.h>
#include <qstring.h>
+#include "qcolorclut_p.h"
+#include "qcolormatrix_p.h"
#include "qcolorspace_p.h"
#include "qcolortrc_p.h"
+#include <array>
+
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc")
+Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc", QtWarningMsg)
+
+namespace QIcc {
struct ICCProfileHeader
{
@@ -90,18 +62,23 @@ constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d)
enum class ColorSpaceType : quint32 {
Rgb = IccTag('R', 'G', 'B', ' '),
Gray = IccTag('G', 'R', 'A', 'Y'),
+ Cmyk = IccTag('C', 'M', 'Y', 'K'),
};
enum class ProfileClass : quint32 {
- Input = IccTag('s', 'c', 'r', 'n'),
+ Input = IccTag('s', 'c', 'n', 'r'),
Display = IccTag('m', 'n', 't', 'r'),
- // Not supported:
Output = IccTag('p', 'r', 't', 'r'),
ColorSpace = IccTag('s', 'p', 'a', 'c'),
+ // Not supported:
+ DeviceLink = IccTag('l', 'i', 'n', 'k'),
+ Abstract = IccTag('a', 'b', 's', 't'),
+ NamedColor = IccTag('n', 'm', 'c', 'l'),
};
enum class Tag : quint32 {
acsp = IccTag('a', 'c', 's', 'p'),
+ Lab_ = IccTag('L', 'a', 'b', ' '),
RGB_ = IccTag('R', 'G', 'B', ' '),
XYZ_ = IccTag('X', 'Y', 'Z', ' '),
rXYZ = IccTag('r', 'X', 'Y', 'Z'),
@@ -113,8 +90,18 @@ enum class Tag : quint32 {
kTRC = IccTag('k', 'T', 'R', 'C'),
A2B0 = IccTag('A', '2', 'B', '0'),
A2B1 = IccTag('A', '2', 'B', '1'),
+ A2B2 = IccTag('A', '2', 'B', '2'),
B2A0 = IccTag('B', '2', 'A', '0'),
B2A1 = IccTag('B', '2', 'A', '1'),
+ B2A2 = IccTag('B', '2', 'A', '2'),
+ B2D0 = IccTag('B', '2', 'D', '0'),
+ B2D1 = IccTag('B', '2', 'D', '1'),
+ B2D2 = IccTag('B', '2', 'D', '2'),
+ B2D3 = IccTag('B', '2', 'D', '3'),
+ D2B0 = IccTag('D', '2', 'B', '0'),
+ D2B1 = IccTag('D', '2', 'B', '1'),
+ D2B2 = IccTag('D', '2', 'B', '2'),
+ D2B3 = IccTag('D', '2', 'B', '3'),
desc = IccTag('d', 'e', 's', 'c'),
text = IccTag('t', 'e', 'x', 't'),
cprt = IccTag('c', 'p', 'r', 't'),
@@ -125,9 +112,11 @@ enum class Tag : quint32 {
mft1 = IccTag('m', 'f', 't', '1'),
mft2 = IccTag('m', 'f', 't', '2'),
mluc = IccTag('m', 'l', 'u', 'c'),
+ mpet = IccTag('m', 'p', 'e', 't'),
mAB_ = IccTag('m', 'A', 'B', ' '),
mBA_ = IccTag('m', 'B', 'A', ' '),
chad = IccTag('c', 'h', 'a', 'd'),
+ gamt = IccTag('g', 'a', 'm', 't'),
sf32 = IccTag('s', 'f', '3', '2'),
// Apple extensions for ICCv2:
@@ -136,7 +125,9 @@ enum class Tag : quint32 {
aabg = IccTag('a', 'a', 'b', 'g'),
};
-inline size_t qHash(const Tag &key, size_t seed = 0)
+} // namespace QIcc
+
+inline size_t qHash(const QIcc::Tag &key, size_t seed = 0)
{
return qHash(quint32(key), seed);
}
@@ -163,18 +154,18 @@ struct XYZTagData : GenericTagData {
struct CurvTagData : GenericTagData {
quint32_be valueCount;
- quint16_be value[1];
+ // followed by curv values: quint16_be[]
};
struct ParaTagData : GenericTagData {
quint16_be curveType;
quint16_be null2;
- quint32_be parameter[1];
+ // followed by parameter values: quint32_be[1-7];
};
struct DescTagData : GenericTagData {
quint32_be asciiDescriptionLength;
- char asciiDescription[1];
+ // followed by ascii description: char[]
// .. we ignore the rest
};
@@ -191,6 +182,46 @@ struct MlucTagData : GenericTagData {
MlucTagRecord records[1];
};
+struct Lut8TagData : GenericTagData {
+ quint8 inputChannels;
+ quint8 outputChannels;
+ quint8 clutGridPoints;
+ quint8 padding;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ // followed by parameter values: quint8[inputChannels * 256];
+ // followed by parameter values: quint8[outputChannels * clutGridPoints^inputChannels];
+ // followed by parameter values: quint8[outputChannels * 256];
+};
+
+struct Lut16TagData : GenericTagData {
+ quint8 inputChannels;
+ quint8 outputChannels;
+ quint8 clutGridPoints;
+ quint8 padding;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ quint16_be inputTableEntries;
+ quint16_be outputTableEntries;
+ // followed by parameter values: quint16_be[inputChannels * inputTableEntries];
+ // followed by parameter values: quint16_be[outputChannels * clutGridPoints^inputChannels];
+ // followed by parameter values: quint16_be[outputChannels * outputTableEntries];
+};
+
// For both mAB and mBA
struct mABTagData : GenericTagData {
quint8 inputChannels;
@@ -201,10 +232,34 @@ struct mABTagData : GenericTagData {
quint32_be mCurvesOffset;
quint32_be clutOffset;
quint32_be aCurvesOffset;
+ // followed by embedded data for the offsets above
+};
+
+struct mpetTagData : GenericTagData {
+ quint16_be inputChannels;
+ quint16_be outputChannels;
+ quint32_be processingElements;
+ // element offset table
+ // element data
};
struct Sf32TagData : GenericTagData {
- quint32_be value[1];
+ quint32_be value[9];
+};
+
+struct MatrixElement {
+ qint32_be e0;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ qint32_be e10;
+ qint32_be e11;
};
static int toFixedS1516(float x)
@@ -235,18 +290,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.profileClass != uint(ProfileClass::ColorSpace)) {
+ 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));
+ && header.inputColorSpace != uint(ColorSpaceType::Gray)
+ && header.inputColorSpace != uint(ColorSpaceType::Cmyk)) {
+ 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));
+ if (header.pcs != uint(Tag::XYZ_) && header.pcs != uint(Tag::Lab_)) {
+ qCInfo(lcIcc, "Invalid ICC profile connection space 0x%x", quint32(header.pcs));
return false;
}
@@ -264,7 +321,7 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
static int writeColorTrc(QDataStream &stream, const QColorTrc &trc)
{
- if (trc.isLinear()) {
+ if (trc.isIdentity()) {
stream << uint(Tag::curv) << uint(0);
stream << uint(0);
return 12;
@@ -304,6 +361,10 @@ static int writeColorTrc(QDataStream &stream, const QColorTrc &trc)
stream << ushort(trc.m_table.m_table8[i] * 257U);
}
}
+ if (trc.m_table.m_tableSize & 1) {
+ stream << ushort(0);
+ return 12 + 2 * trc.m_table.m_tableSize + 2;
+ }
return 12 + 2 * trc.m_table.m_tableSize;
}
@@ -313,10 +374,21 @@ QByteArray toIccProfile(const QColorSpace &space)
return QByteArray();
const QColorSpacePrivate *spaceDPtr = QColorSpacePrivate::get(space);
+ // This should catch anything not three component matrix based as we can only get that from parsed ICC
+ if (!spaceDPtr->iccProfile.isEmpty())
+ return spaceDPtr->iccProfile;
+ Q_ASSERT(spaceDPtr->isThreeComponentMatrix());
+
+ int fixedLengthTagCount = 5;
+ bool writeChad = false;
+ if (!spaceDPtr->whitePoint.isNull() && spaceDPtr->whitePoint != QColorVector::D50()) {
+ writeChad = true;
+ fixedLengthTagCount++;
+ }
- constexpr int tagCount = 9;
- constexpr uint profileDataOffset = 128 + 4 + 12 * tagCount;
- constexpr uint variableTagTableOffsets = 128 + 4 + 12 * 5;
+ const int tagCount = fixedLengthTagCount + 4;
+ const uint profileDataOffset = 128 + 4 + 12 * tagCount;
+ const uint variableTagTableOffsets = 128 + 4 + 12 * fixedLengthTagCount;
uint currentOffset = 0;
uint rTrcOffset, gTrcOffset, bTrcOffset;
uint rTrcSize, gTrcSize, bTrcSize;
@@ -329,10 +401,10 @@ QByteArray toIccProfile(const QColorSpace &space)
// Profile header:
stream << uint(0); // Size, we will update this later
stream << uint(0);
- stream << uint(0x02400000); // Version 2.4 (note we use 'para' from version 4)
+ stream << uint(0x04400000); // Version 4.4
stream << uint(ProfileClass::Display);
stream << uint(Tag::RGB_);
- stream << uint(Tag::XYZ_);
+ stream << (spaceDPtr->isPcsLab ? uint(Tag::Lab_) : uint(Tag::XYZ_));
stream << uint(0) << uint(0) << uint(0);
stream << uint(Tag::acsp);
stream << uint(0) << uint(0) << uint(0);
@@ -346,19 +418,23 @@ QByteArray toIccProfile(const QColorSpace &space)
stream << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0);
// Tag table:
+ currentOffset = profileDataOffset;
stream << uint(tagCount);
stream << uint(Tag::rXYZ) << uint(profileDataOffset + 00) << uint(20);
stream << uint(Tag::gXYZ) << uint(profileDataOffset + 20) << uint(20);
stream << uint(Tag::bXYZ) << uint(profileDataOffset + 40) << uint(20);
stream << uint(Tag::wtpt) << uint(profileDataOffset + 60) << uint(20);
- stream << uint(Tag::cprt) << uint(profileDataOffset + 80) << uint(12);
+ stream << uint(Tag::cprt) << uint(profileDataOffset + 80) << uint(34);
+ currentOffset += 20 + 20 + 20 + 20 + 34 + 2;
+ if (writeChad) {
+ stream << uint(Tag::chad) << uint(currentOffset) << uint(44);
+ currentOffset += 44;
+ }
// From here the offset and size will be updated later:
stream << uint(Tag::rTRC) << uint(0) << uint(0);
stream << uint(Tag::gTRC) << uint(0) << uint(0);
stream << uint(Tag::bTRC) << uint(0) << uint(0);
stream << uint(Tag::desc) << uint(0) << uint(0);
- // TODO: consider adding 'chad' tag (required in ICC >=4 when we have non-D50 whitepoint)
- currentOffset = profileDataOffset;
// Tag data:
stream << uint(Tag::XYZ_) << uint(0);
@@ -377,9 +453,25 @@ QByteArray toIccProfile(const QColorSpace &space)
stream << toFixedS1516(spaceDPtr->whitePoint.x);
stream << toFixedS1516(spaceDPtr->whitePoint.y);
stream << toFixedS1516(spaceDPtr->whitePoint.z);
- stream << uint(Tag::text) << uint(0);
- stream << uint(IccTag('N', '/', 'A', '\0'));
- currentOffset += 92;
+ stream << uint(Tag::mluc) << uint(0);
+ stream << uint(1) << uint(12);
+ stream << uchar('e') << uchar('n') << uchar('U') << uchar('S');
+ stream << uint(6) << uint(28);
+ stream << ushort('N') << ushort('/') << ushort('A');
+ stream << ushort(0); // 4-byte alignment
+ if (writeChad) {
+ QColorMatrix chad = QColorMatrix::chromaticAdaptation(spaceDPtr->whitePoint);
+ stream << uint(Tag::sf32) << uint(0);
+ stream << toFixedS1516(chad.r.x);
+ stream << toFixedS1516(chad.g.x);
+ stream << toFixedS1516(chad.b.x);
+ stream << toFixedS1516(chad.r.y);
+ stream << toFixedS1516(chad.g.y);
+ stream << toFixedS1516(chad.b.y);
+ stream << toFixedS1516(chad.r.z);
+ stream << toFixedS1516(chad.g.z);
+ stream << toFixedS1516(chad.b.z);
+ }
// From now on the data is variable sized:
rTrcOffset = currentOffset;
@@ -402,16 +494,20 @@ QByteArray toIccProfile(const QColorSpace &space)
currentOffset += bTrcSize;
}
+ // Writing description
descOffset = currentOffset;
- QByteArray description = spaceDPtr->description.toUtf8();
- stream << uint(Tag::desc) << uint(0);
- stream << uint(description.size() + 1);
- stream.writeRawData(description.constData(), description.size() + 1);
- stream << uint(0) << uint(0);
- stream << ushort(0) << uchar(0);
- QByteArray macdesc(67, '\0');
- stream.writeRawData(macdesc.constData(), 67);
- descSize = 90 + description.size() + 1;
+ const QString description = space.description();
+ stream << uint(Tag::mluc) << uint(0);
+ stream << uint(1) << uint(12);
+ stream << uchar('e') << uchar('n') << uchar('U') << uchar('S');
+ stream << uint(description.size() * 2) << uint(28);
+ for (QChar ch : description)
+ stream << ushort(ch.unicode());
+ descSize = 28 + description.size() * 2;
+ if (description.size() & 1) {
+ stream << ushort(0);
+ currentOffset += 2;
+ }
currentOffset += descSize;
buffer.close();
@@ -442,49 +538,55 @@ struct TagEntry {
quint32 size;
};
-bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector &colorVector)
+static bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector &colorVector)
{
if (tagEntry.size < sizeof(XYZTagData)) {
qCWarning(lcIcc) << "Undersized XYZ tag";
return false;
}
- const XYZTagData *xyz = reinterpret_cast<const XYZTagData *>(data.constData() + tagEntry.offset);
- if (xyz->type != quint32(Tag::XYZ_)) {
+ const XYZTagData xyz = qFromUnaligned<XYZTagData>(data.constData() + tagEntry.offset);
+ if (xyz.type != quint32(Tag::XYZ_)) {
qCWarning(lcIcc) << "Bad XYZ content type";
return false;
}
- const float x = fromFixedS1516(xyz->fixedX);
- const float y = fromFixedS1516(xyz->fixedY);
- const float z = fromFixedS1516(xyz->fixedZ);
+ const float x = fromFixedS1516(xyz.fixedX);
+ const float y = fromFixedS1516(xyz.fixedY);
+ const float z = fromFixedS1516(xyz.fixedZ);
colorVector = QColorVector(x, y, z);
return true;
}
-bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma)
+static quint32 parseTRC(const QByteArrayView &tagData, QColorTrc &gamma, QColorTransferTable::Type type = QColorTransferTable::TwoWay)
{
- const GenericTagData *trcData = reinterpret_cast<const GenericTagData *>(data.constData() + tagEntry.offset);
- if (trcData->type == quint32(Tag::curv)) {
- const CurvTagData *curv = static_cast<const CurvTagData *>(trcData);
- if (curv->valueCount > (1 << 16))
- return false;
- if (tagEntry.size - 12 < 2 * curv->valueCount)
- return false;
- if (curv->valueCount == 0) {
+ const GenericTagData trcData = qFromUnaligned<GenericTagData>(tagData.constData());
+ if (trcData.type == quint32(Tag::curv)) {
+ Q_STATIC_ASSERT(sizeof(CurvTagData) == 12);
+ const CurvTagData curv = qFromUnaligned<CurvTagData>(tagData.constData());
+ if (curv.valueCount > (1 << 16))
+ return 0;
+ if (tagData.size() < qsizetype(12 + 2 * curv.valueCount))
+ return 0;
+ const auto valueOffset = 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);
+ } else if (curv.valueCount == 1) {
+ const quint16 v = qFromBigEndian<quint16>(tagData.constData() + valueOffset);
gamma.m_type = QColorTrc::Type::Function;
- gamma.m_fun = QColorTransferFunction::fromGamma(g);
+ gamma.m_fun = QColorTransferFunction::fromGamma(v * (1.0f / 256.0f));
} else {
- QVector<quint16> tabl;
- tabl.resize(curv->valueCount);
- for (uint i = 0; i < curv->valueCount; ++i)
- tabl[i] = curv->value[i];
- QColorTransferTable table = QColorTransferTable(curv->valueCount, std::move(tabl));
+ 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.");
+ qFromBigEndian<quint16>(tagData.constData() + valueOffset, curv.valueCount, tabl.data());
+ QColorTransferTable table(curv.valueCount, tabl, type);
QColorTransferFunction curve;
- if (!table.asColorTransferFunction(&curve)) {
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Invalid curv table";
+ return 0;
+ } else if (!table.asColorTransferFunction(&curve)) {
gamma.m_type = QColorTrc::Type::Table;
gamma.m_table = table;
} else {
@@ -493,262 +595,601 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
gamma.m_fun = curve;
}
}
- return true;
+ return 12 + 2 * curv.valueCount;
}
- if (trcData->type == quint32(Tag::para)) {
- if (tagEntry.size < sizeof(ParaTagData))
- return false;
- const ParaTagData *para = static_cast<const ParaTagData *>(trcData);
- switch (para->curveType) {
+ if (trcData.type == quint32(Tag::para)) {
+ Q_STATIC_ASSERT(sizeof(ParaTagData) == 12);
+ const ParaTagData para = qFromUnaligned<ParaTagData>(tagData.constData());
+ const auto parametersOffset = sizeof(ParaTagData);
+ quint32 parameters[7];
+ switch (para.curveType) {
case 0: {
- float g = fromFixedS1516(para->parameter[0]);
+ if (tagData.size() < 12 + 1 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 1, parameters);
+ float g = fromFixedS1516(parameters[0]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction::fromGamma(g);
- break;
+ return 12 + 1 * 4;
}
case 1: {
- if (tagEntry.size < sizeof(ParaTagData) + 2 * 4)
- return false;
- float g = fromFixedS1516(para->parameter[0]);
- float a = fromFixedS1516(para->parameter[1]);
- float b = fromFixedS1516(para->parameter[2]);
+ if (tagData.size() < 12 + 3 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 3, parameters);
+ if (parameters[1] == 0)
+ return 0;
+ float g = fromFixedS1516(parameters[0]);
+ float a = fromFixedS1516(parameters[1]);
+ float b = fromFixedS1516(parameters[2]);
float d = -b / a;
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, 0.0f, 0.0f, g);
- break;
+ return 12 + 3 * 4;
}
case 2: {
- if (tagEntry.size < sizeof(ParaTagData) + 3 * 4)
- return false;
- float g = fromFixedS1516(para->parameter[0]);
- float a = fromFixedS1516(para->parameter[1]);
- float b = fromFixedS1516(para->parameter[2]);
- float c = fromFixedS1516(para->parameter[3]);
+ if (tagData.size() < 12 + 4 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 4, parameters);
+ if (parameters[1] == 0)
+ return 0;
+ float g = fromFixedS1516(parameters[0]);
+ float a = fromFixedS1516(parameters[1]);
+ float b = fromFixedS1516(parameters[2]);
+ float c = fromFixedS1516(parameters[3]);
float d = -b / a;
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, c, c, g);
- break;
+ return 12 + 4 * 4;
}
case 3: {
- if (tagEntry.size < sizeof(ParaTagData) + 4 * 4)
- return false;
- float g = fromFixedS1516(para->parameter[0]);
- float a = fromFixedS1516(para->parameter[1]);
- float b = fromFixedS1516(para->parameter[2]);
- float c = fromFixedS1516(para->parameter[3]);
- float d = fromFixedS1516(para->parameter[4]);
+ if (tagData.size() < 12 + 5 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 5, parameters);
+ float g = fromFixedS1516(parameters[0]);
+ float a = fromFixedS1516(parameters[1]);
+ float b = fromFixedS1516(parameters[2]);
+ float c = fromFixedS1516(parameters[3]);
+ float d = fromFixedS1516(parameters[4]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, c, d, 0.0f, 0.0f, g);
- break;
+ return 12 + 5 * 4;
}
case 4: {
- if (tagEntry.size < sizeof(ParaTagData) + 6 * 4)
- return false;
- float g = fromFixedS1516(para->parameter[0]);
- float a = fromFixedS1516(para->parameter[1]);
- float b = fromFixedS1516(para->parameter[2]);
- float c = fromFixedS1516(para->parameter[3]);
- float d = fromFixedS1516(para->parameter[4]);
- float e = fromFixedS1516(para->parameter[5]);
- float f = fromFixedS1516(para->parameter[6]);
+ if (tagData.size() < 12 + 7 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 7, parameters);
+ float g = fromFixedS1516(parameters[0]);
+ float a = fromFixedS1516(parameters[1]);
+ float b = fromFixedS1516(parameters[2]);
+ float c = fromFixedS1516(parameters[3]);
+ float d = fromFixedS1516(parameters[4]);
+ float e = fromFixedS1516(parameters[5]);
+ float f = fromFixedS1516(parameters[6]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, c, d, e, f, g);
- break;
+ return 12 + 7 * 4;
}
default:
- qCWarning(lcIcc) << "Unknown para type" << uint(para->curveType);
- return false;
+ qCWarning(lcIcc) << "Unknown para type" << uint(para.curveType);
+ return 0;
}
return true;
}
- qCWarning(lcIcc) << "Invalid TRC data type";
- return false;
+ qCWarning(lcIcc) << "Invalid TRC data type" << Qt::hex << trcData.type;
+ return 0;
}
-bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descName)
+template<typename T>
+static void parseCLUT(const T *tableData, const float f, QColorCLUT *clut, uchar outputChannels)
{
- const GenericTagData *tag = (const GenericTagData *)(data.constData() + tagEntry.offset);
+ if (outputChannels == 4) {
+ for (qsizetype index = 0; index < clut->table.size(); ++index) {
+ QColorVector v(tableData[index * 4 + 0] * f,
+ tableData[index * 4 + 1] * f,
+ tableData[index * 4 + 2] * f,
+ tableData[index * 4 + 3] * f);
+ clut->table[index] = v;
+ };
+ } else {
+ for (qsizetype index = 0; index < clut->table.size(); ++index) {
+ QColorVector v(tableData[index * 3 + 0] * f,
+ tableData[index * 3 + 1] * f,
+ tableData[index * 3 + 2] * f);
+ clut->table[index] = v;
+ };
+ }
+}
- // Either 'desc' (ICCv2) or 'mluc' (ICCv4)
- if (tag->type == quint32(Tag::desc)) {
- if (tagEntry.size < sizeof(DescTagData))
- return false;
- const DescTagData *desc = (const DescTagData *)(data.constData() + tagEntry.offset);
- const quint32 len = desc->asciiDescriptionLength;
- if (len < 1)
+// very simple version for small values (<=4) of exp.
+static constexpr qsizetype intPow(qsizetype x, qsizetype exp)
+{
+ return (exp <= 1) ? x : x * intPow(x, exp - 1);
+}
+
+// Parses lut8 and lut16 type elements
+template<typename T>
+static bool parseLutData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
+{
+ if (tagEntry.size < sizeof(T)) {
+ qCWarning(lcIcc) << "Undersized lut8/lut16 tag";
+ return false;
+ }
+ if (qsizetype(tagEntry.size) > data.size()) {
+ qCWarning(lcIcc) << "Truncated lut8/lut16 tag";
+ return false;
+ }
+ using S = std::conditional_t<std::is_same_v<T, Lut8TagData>, uint8_t, uint16_t>;
+ const T lut = qFromUnaligned<T>(data.constData() + tagEntry.offset);
+ int inputTableEntries, outputTableEntries, precision;
+ if constexpr (std::is_same_v<T, Lut8TagData>) {
+ Q_ASSERT(lut.type == quint32(Tag::mft1));
+ if (!colorSpacePrivate->isPcsLab && isAb) {
+ qCWarning(lcIcc) << "Lut8 can not output XYZ values";
return false;
- if (tagEntry.size - 12 < len)
+ }
+ inputTableEntries = 256;
+ outputTableEntries = 256;
+ precision = 1;
+ } else {
+ Q_ASSERT(lut.type == quint32(Tag::mft2));
+ inputTableEntries = lut.inputTableEntries;
+ outputTableEntries = lut.outputTableEntries;
+ if (inputTableEntries < 2 || inputTableEntries > 4096)
return false;
- if (desc->asciiDescription[len - 1] != '\0')
+ if (outputTableEntries < 2 || outputTableEntries > 4096)
return false;
- descName = QString::fromLatin1(desc->asciiDescription, len - 1);
- return true;
+ precision = 2;
}
- if (tag->type != quint32(Tag::mluc))
- return false;
- if (tagEntry.size < sizeof(MlucTagData))
+ bool inTableIsLinear = true, outTableIsLinear = true;
+ QColorSpacePrivate::TransferElement inTableElement;
+ QColorSpacePrivate::TransferElement outTableElement;
+ QColorCLUT clutElement;
+ QColorMatrix matrixElement;
+
+ matrixElement.r.x = fromFixedS1516(lut.e1);
+ matrixElement.g.x = fromFixedS1516(lut.e2);
+ matrixElement.b.x = fromFixedS1516(lut.e3);
+ matrixElement.r.y = fromFixedS1516(lut.e4);
+ matrixElement.g.y = fromFixedS1516(lut.e5);
+ matrixElement.b.y = fromFixedS1516(lut.e6);
+ matrixElement.r.z = fromFixedS1516(lut.e7);
+ matrixElement.g.z = fromFixedS1516(lut.e8);
+ matrixElement.b.z = fromFixedS1516(lut.e9);
+ if (!colorSpacePrivate->isPcsLab && !isAb && !matrixElement.isValid()) {
+ qCWarning(lcIcc) << "Invalid matrix values in lut8/lut16";
return false;
- const MlucTagData *mluc = (const MlucTagData *)(data.constData() + tagEntry.offset);
- if (mluc->recordCount < 1)
+ }
+
+ if (lut.inputChannels != 3 && !(isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && lut.inputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported lut8/lut16 input channel count" << lut.inputChannels;
return false;
- if (mluc->recordSize < 12)
+ }
+
+ if (lut.outputChannels != 3 && !(!isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && lut.outputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported lut8/lut16 output channel count" << lut.outputChannels;
return false;
- // We just use the primary record regardless of language or country.
- const quint32 stringOffset = mluc->records[0].offset;
- const quint32 stringSize = mluc->records[0].size;
- if (tagEntry.size < stringOffset || tagEntry.size - stringOffset < stringSize )
+ }
+
+ const qsizetype clutTableSize = intPow(lut.clutGridPoints, lut.inputChannels);
+ if (tagEntry.size < (sizeof(T) + precision * lut.inputChannels * inputTableEntries
+ + precision * lut.outputChannels * outputTableEntries
+ + precision * lut.outputChannels * clutTableSize)) {
+ qCWarning(lcIcc) << "Undersized lut8/lut16 tag, no room for tables";
return false;
- if ((stringSize | stringOffset) & 1)
+ }
+ if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && clutTableSize == 0) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
return false;
- quint32 stringLen = stringSize / 2;
- const ushort *unicodeString = (const ushort *)(data.constData() + tagEntry.offset + stringOffset);
- // The given length shouldn't include 0-termination, but might.
- if (stringLen > 1 && unicodeString[stringLen - 1] == 0)
- --stringLen;
- QVarLengthArray<char16_t> utf16hostendian(stringLen);
- qFromBigEndian<char16_t>(unicodeString, stringLen, utf16hostendian.data());
- descName = QString::fromUtf16(utf16hostendian.data(), stringLen);
+ }
+
+ const uint8_t *tableData = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + sizeof(T));
+
+ for (int j = 0; j < lut.inputChannels; ++j) {
+ QList<S> input(inputTableEntries);
+ qFromBigEndian<S>(tableData, inputTableEntries, input.data());
+ QColorTransferTable table(inputTableEntries, input, QColorTransferTable::OneWay);
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Bad input table in lut8/lut16";
+ return false;
+ }
+ if (!table.isIdentity())
+ inTableIsLinear = false;
+ inTableElement.trc[j] = std::move(table);
+ tableData += inputTableEntries * precision;
+ }
+
+ clutElement.table.resize(clutTableSize);
+ clutElement.gridPointsX = clutElement.gridPointsY = clutElement.gridPointsZ = lut.clutGridPoints;
+ if (lut.inputChannels == 4)
+ clutElement.gridPointsW = lut.clutGridPoints;
+
+ if constexpr (std::is_same_v<T, Lut8TagData>) {
+ parseCLUT(tableData, 1.f / 255.f, &clutElement, lut.outputChannels);
+ } else {
+ float f = 1.0f / 65535.f;
+ if (colorSpacePrivate->isPcsLab && isAb) // Legacy lut16 conversion to Lab
+ f = 1.0f / 65280.f;
+ QList<S> clutTable(clutTableSize * lut.outputChannels);
+ qFromBigEndian<S>(tableData, clutTable.size(), clutTable.data());
+ parseCLUT(clutTable.constData(), f, &clutElement, lut.outputChannels);
+ }
+ tableData += clutTableSize * lut.outputChannels * precision;
+
+ for (int j = 0; j < lut.outputChannels; ++j) {
+ QList<S> output(outputTableEntries);
+ qFromBigEndian<S>(tableData, outputTableEntries, output.data());
+ QColorTransferTable table(outputTableEntries, output, QColorTransferTable::OneWay);
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Bad output table in lut8/lut16";
+ return false;
+ }
+ if (!table.isIdentity())
+ outTableIsLinear = false;
+ outTableElement.trc[j] = std::move(table);
+ tableData += outputTableEntries * precision;
+ }
+
+ if (isAb) {
+ if (!inTableIsLinear)
+ colorSpacePrivate->mAB.append(inTableElement);
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mAB.append(clutElement);
+ if (!outTableIsLinear || colorSpacePrivate->mAB.isEmpty())
+ colorSpacePrivate->mAB.append(outTableElement);
+ } else {
+ // The matrix is only to be applied if the input color-space is XYZ
+ if (!colorSpacePrivate->isPcsLab && !matrixElement.isIdentity())
+ colorSpacePrivate->mBA.append(matrixElement);
+ if (!inTableIsLinear)
+ colorSpacePrivate->mBA.append(inTableElement);
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mBA.append(clutElement);
+ if (!outTableIsLinear || colorSpacePrivate->mBA.isEmpty())
+ colorSpacePrivate->mBA.append(outTableElement);
+ }
return true;
}
-bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
+// Parses mAB and mBA type elements
+static bool parseMabData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
{
- Q_ASSERT((reinterpret_cast<qintptr>(data.constData()) & 0x3) == 0);
- if (reinterpret_cast<qintptr>(data.constData()) & 0x3) {
- qCWarning(lcIcc) << "fromIccProfile: Unaligned profile data";
+ if (tagEntry.size < sizeof(mABTagData)) {
+ qCWarning(lcIcc) << "Undersized mAB/mBA tag";
return false;
}
- if (data.size() < qsizetype(sizeof(ICCProfileHeader))) {
- qCWarning(lcIcc) << "fromIccProfile: failed size sanity 1";
+ if (qsizetype(tagEntry.size) > data.size()) {
+ qCWarning(lcIcc) << "Truncated mAB/mBA tag";
return false;
}
- const ICCProfileHeader *header = (const ICCProfileHeader *)data.constData();
- if (!isValidIccProfile(*header))
- return false; // if failed we already printing a warning
- if (qsizetype(header->profileSize) > data.size()) {
- qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2";
+ const mABTagData mab = qFromUnaligned<mABTagData>(data.constData() + tagEntry.offset);
+ if ((mab.type != quint32(Tag::mAB_) && isAb) || (mab.type != quint32(Tag::mBA_) && !isAb)){
+ qCWarning(lcIcc) << "Bad mAB/mBA content type";
return false;
}
- // Read tag index
- const TagTableEntry *tagTable = (const TagTableEntry *)(data.constData() + sizeof(ICCProfileHeader));
- const qsizetype offsetToData = sizeof(ICCProfileHeader) + header->tagCount * sizeof(TagTableEntry);
- Q_ASSERT(offsetToData > 0);
- if (offsetToData > data.size()) {
- qCWarning(lcIcc) << "fromIccProfile: failed index size sanity";
+ if (mab.inputChannels != 3 && !(isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && mab.inputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported mAB/mBA input channel count" << mab.inputChannels;
return false;
}
- QHash<Tag, TagEntry> tagIndex;
- for (uint i = 0; i < header->tagCount; ++i) {
- // Sanity check tag sizes and offsets:
- if (qsizetype(tagTable[i].offset) < offsetToData) {
- qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 1";
+ if (mab.outputChannels != 3 && !(!isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && mab.outputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported mAB/mBA output channel count" << mab.outputChannels;
+ return false;
+ }
+
+ // These combinations are legal: B, M + Matrix + B, A + Clut + B, A + Clut + M + Matrix + B
+ if (!mab.bCurvesOffset) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA without B table";
+ return false;
+ }
+ if (((bool)mab.matrixOffset != (bool)mab.mCurvesOffset) ||
+ ((bool)mab.aCurvesOffset != (bool)mab.clutOffset)) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA element combination";
+ return false;
+ }
+
+ if (mab.aCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.bCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.mCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.matrixOffset > (tagEntry.size - 4 * 12) ||
+ mab.clutOffset > (tagEntry.size - 20)) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA element offset";
+ return false;
+ }
+
+ QColorSpacePrivate::TransferElement bTableElement;
+ QColorSpacePrivate::TransferElement aTableElement;
+ QColorCLUT clutElement;
+ QColorSpacePrivate::TransferElement mTableElement;
+ QColorMatrix matrixElement;
+ QColorVector offsetElement;
+
+ auto parseCurves = [&data, &tagEntry] (uint curvesOffset, QColorTrc *table, int channels) {
+ for (int i = 0; i < channels; ++i) {
+ if (qsizetype(tagEntry.offset + curvesOffset + 12) > data.size() || curvesOffset + 12 > tagEntry.size) {
+ qCWarning(lcIcc) << "Space missing for channel curves in mAB/mBA";
+ return false;
+ }
+ auto size = parseTRC(QByteArrayView(data).sliced(tagEntry.offset + curvesOffset, tagEntry.size - curvesOffset), table[i], QColorTransferTable::OneWay);
+ if (!size)
+ return false;
+ if (size & 2) size += 2; // possible padding
+ curvesOffset += size;
+ }
+ return true;
+ };
+
+ bool bCurvesAreLinear = true, aCurvesAreLinear = true, mCurvesAreLinear = true;
+
+ // B Curves
+ if (!parseCurves(mab.bCurvesOffset, bTableElement.trc, isAb ? mab.outputChannels : mab.inputChannels)) {
+ qCWarning(lcIcc) << "Invalid B curves";
+ return false;
+ } else {
+ bCurvesAreLinear = bTableElement.trc[0].isIdentity() && bTableElement.trc[1].isIdentity() && bTableElement.trc[2].isIdentity();
+ }
+
+ // A Curves
+ if (mab.aCurvesOffset) {
+ if (!parseCurves(mab.aCurvesOffset, aTableElement.trc, isAb ? mab.inputChannels : mab.outputChannels)) {
+ qCWarning(lcIcc) << "Invalid A curves";
return false;
+ } else {
+ aCurvesAreLinear = aTableElement.trc[0].isIdentity() && aTableElement.trc[1].isIdentity() && aTableElement.trc[2].isIdentity();
}
- // Checked separately from (+ size) to handle overflow.
- if (tagTable[i].offset > header->profileSize) {
- qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 2";
+ }
+
+ // M Curves
+ if (mab.mCurvesOffset) {
+ if (!parseCurves(mab.mCurvesOffset, mTableElement.trc, 3)) {
+ qCWarning(lcIcc) << "Invalid M curves";
return false;
+ } else {
+ mCurvesAreLinear = mTableElement.trc[0].isIdentity() && mTableElement.trc[1].isIdentity() && mTableElement.trc[2].isIdentity();
}
- if (tagTable[i].size < 12) {
- qCWarning(lcIcc) << "fromIccProfile: failed minimal tag size sanity";
+ }
+
+ // Matrix
+ if (mab.matrixOffset) {
+ const MatrixElement matrix = qFromUnaligned<MatrixElement>(data.constData() + tagEntry.offset + mab.matrixOffset);
+ matrixElement.r.x = fromFixedS1516(matrix.e0);
+ matrixElement.g.x = fromFixedS1516(matrix.e1);
+ matrixElement.b.x = fromFixedS1516(matrix.e2);
+ matrixElement.r.y = fromFixedS1516(matrix.e3);
+ matrixElement.g.y = fromFixedS1516(matrix.e4);
+ matrixElement.b.y = fromFixedS1516(matrix.e5);
+ matrixElement.r.z = fromFixedS1516(matrix.e6);
+ matrixElement.g.z = fromFixedS1516(matrix.e7);
+ matrixElement.b.z = fromFixedS1516(matrix.e8);
+ offsetElement.x = fromFixedS1516(matrix.e9);
+ offsetElement.y = fromFixedS1516(matrix.e10);
+ offsetElement.z = fromFixedS1516(matrix.e11);
+ if (!matrixElement.isValid() || !offsetElement.isValid()) {
+ qCWarning(lcIcc) << "Invalid matrix values in mAB/mBA element";
return false;
}
- if (tagTable[i].size > header->profileSize - tagTable[i].offset) {
- qCWarning(lcIcc) << "fromIccProfile: failed tag offset + size sanity";
+ }
+
+ // CLUT
+ if (mab.clutOffset) {
+ clutElement.gridPointsX = uint8_t(data[tagEntry.offset + mab.clutOffset]);
+ clutElement.gridPointsY = uint8_t(data[tagEntry.offset + mab.clutOffset + 1]);
+ clutElement.gridPointsZ = uint8_t(data[tagEntry.offset + mab.clutOffset + 2]);
+ clutElement.gridPointsW = std::max(uint8_t(data[tagEntry.offset + mab.clutOffset + 3]), uint8_t(1));
+ const uchar precision = data[tagEntry.offset + mab.clutOffset + 16];
+ if (precision > 2 || precision < 1) {
+ qCWarning(lcIcc) << "Invalid mAB/mBA element CLUT precision";
return false;
}
- if (tagTable[i].offset & 0x03) {
- qCWarning(lcIcc) << "fromIccProfile: invalid tag offset alignment";
+ if (clutElement.gridPointsX < 2 || clutElement.gridPointsY < 2 || clutElement.gridPointsZ < 2) {
+ qCWarning(lcIcc) << "Empty CLUT";
return false;
}
-// printf("'%4s' %d %d\n", (const char *)&tagTable[i].signature,
-// quint32(tagTable[i].offset),
-// quint32(tagTable[i].size));
- tagIndex.insert(Tag(quint32(tagTable[i].signature)), { tagTable[i].offset, tagTable[i].size });
+ const qsizetype clutTableSize = clutElement.gridPointsX * clutElement.gridPointsY * clutElement.gridPointsZ * clutElement.gridPointsW;
+ if ((mab.clutOffset + 20 + clutTableSize * mab.outputChannels * precision) > tagEntry.size) {
+ qCWarning(lcIcc) << "CLUT oversized for tag";
+ return false;
+ }
+
+ clutElement.table.resize(clutTableSize);
+ if (precision == 2) {
+ QList<uint16_t> clutTable(clutTableSize * mab.outputChannels);
+ qFromBigEndian<uint16_t>(data.constData() + tagEntry.offset + mab.clutOffset + 20, clutTable.size(), clutTable.data());
+ parseCLUT(clutTable.constData(), (1.f/65535.f), &clutElement, mab.outputChannels);
+ } else {
+ const uint8_t *clutTable = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + mab.clutOffset + 20);
+ parseCLUT(clutTable, (1.f/255.f), &clutElement, mab.outputChannels);
+ }
+ } else if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
+ return false;
}
- // Check the profile is three-component matrix based (what we currently support):
- if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) {
- 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";
- return false;
+ if (isAb) {
+ if (mab.aCurvesOffset) {
+ if (!aCurvesAreLinear)
+ colorSpacePrivate->mAB.append(std::move(aTableElement));
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mAB.append(std::move(clutElement));
+ }
+ if (mab.mCurvesOffset && mab.outputChannels == 3) {
+ if (!mCurvesAreLinear)
+ colorSpacePrivate->mAB.append(std::move(mTableElement));
+ if (!matrixElement.isIdentity())
+ colorSpacePrivate->mAB.append(std::move(matrixElement));
+ if (!offsetElement.isNull())
+ colorSpacePrivate->mAB.append(std::move(offsetElement));
}
+ if (!bCurvesAreLinear|| colorSpacePrivate->mAB.isEmpty())
+ colorSpacePrivate->mAB.append(std::move(bTableElement));
} else {
- Q_ASSERT(header->inputColorSpace == uint(ColorSpaceType::Gray));
- if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - not valid gray scale based";
- return false;
+ if (!bCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(bTableElement));
+ if (mab.mCurvesOffset && mab.inputChannels == 3) {
+ if (!matrixElement.isIdentity())
+ colorSpacePrivate->mBA.append(std::move(matrixElement));
+ if (!offsetElement.isNull())
+ colorSpacePrivate->mBA.append(std::move(offsetElement));
+ if (!mCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(mTableElement));
+ }
+ if (mab.aCurvesOffset) {
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mBA.append(std::move(clutElement));
+ if (!aCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(aTableElement));
}
+ if (colorSpacePrivate->mBA.isEmpty()) // Ensure non-empty to indicate valid empty transform
+ colorSpacePrivate->mBA.append(std::move(bTableElement));
}
- QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::getWritable(*colorSpace);
+ return true;
+}
- if (header->inputColorSpace == uint(ColorSpaceType::Rgb)) {
- // Parse XYZ tags
- if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r))
- return false;
- if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g))
+static bool parseA2B(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *privat, bool isAb)
+{
+ const GenericTagData a2bData = qFromUnaligned<GenericTagData>(data.constData() + tagEntry.offset);
+ if (a2bData.type == quint32(Tag::mft1))
+ return parseLutData<Lut8TagData>(data, tagEntry, privat, isAb);
+ else if (a2bData.type == quint32(Tag::mft2))
+ return parseLutData<Lut16TagData>(data, tagEntry, privat, isAb);
+ else if (a2bData.type == quint32(Tag::mAB_) || a2bData.type == quint32(Tag::mBA_))
+ return parseMabData(data, tagEntry, privat, isAb);
+
+ qCWarning(lcIcc) << "fromIccProfile: Unknown A2B/B2A data type";
+ return false;
+}
+
+static bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descName)
+{
+ const GenericTagData tag = qFromUnaligned<GenericTagData>(data.constData() + tagEntry.offset);
+
+ // Either 'desc' (ICCv2) or 'mluc' (ICCv4)
+ if (tag.type == quint32(Tag::desc)) {
+ Q_STATIC_ASSERT(sizeof(DescTagData) == 12);
+ const DescTagData desc = qFromUnaligned<DescTagData>(data.constData() + tagEntry.offset);
+ const quint32 len = desc.asciiDescriptionLength;
+ if (len < 1)
return false;
- if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b))
+ if (tagEntry.size - 12 < len)
return false;
- if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint))
+ const char *asciiDescription = data.constData() + tagEntry.offset + sizeof(DescTagData);
+ if (asciiDescription[len - 1] != '\0')
return false;
+ descName = QString::fromLatin1(asciiDescription, len - 1);
+ return true;
+ }
+ if (tag.type != quint32(Tag::mluc))
+ return false;
- colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
- if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
- qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
- }
- if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb;
- }
- } else {
- // We will use sRGB primaries and fit to match the given white-point if
- // it doesn't match sRGB's.
- QColorVector whitePoint;
- if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint))
- return false;
- if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z - whitePoint.x) == 0.0f) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized";
- return false;
- }
- if (whitePoint == QColorVector::D65()) {
- colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
- } 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 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";
- return false;
- }
- colorspaceDPtr->toXyz = primaries.toXyzMatrix();
- }
+ if (tagEntry.size < sizeof(MlucTagData))
+ return false;
+ const MlucTagData mluc = qFromUnaligned<MlucTagData>(data.constData() + tagEntry.offset);
+ if (mluc.recordCount < 1)
+ return false;
+ if (mluc.recordSize != 12)
+ return false;
+ // We just use the primary record regardless of language or country.
+ const quint32 stringOffset = mluc.records[0].offset;
+ const quint32 stringSize = mluc.records[0].size;
+ if (tagEntry.size < stringOffset || tagEntry.size - stringOffset < stringSize )
+ return false;
+ if ((stringSize | stringOffset) & 1)
+ return false;
+ quint32 stringLen = stringSize / 2;
+ QVarLengthArray<char16_t> utf16hostendian(stringLen);
+ qFromBigEndian<char16_t>(data.constData() + tagEntry.offset + stringOffset, stringLen,
+ utf16hostendian.data());
+ // The given length shouldn't include 0-termination, but might.
+ if (stringLen > 1 && utf16hostendian[stringLen - 1] == 0)
+ --stringLen;
+ descName = QString::fromUtf16(utf16hostendian.data(), stringLen);
+ return true;
+}
+
+static bool parseRgbMatrix(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr)
+{
+ // Parse XYZ tags
+ if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint))
+ return false;
+ if (!colorspaceDPtr->toXyz.isValid() || !colorspaceDPtr->whitePoint.isValid() || colorspaceDPtr->whitePoint.isNull()) {
+ qCWarning(lcIcc) << "Invalid XYZ values in RGB matrix";
+ return false;
}
- // Reset the matrix to our canonical values:
- if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom)
- colorspaceDPtr->setToXyzMatrix();
- // Parse TRC tags
+ colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
+ if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
+ } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb;
+ } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
+ qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
+ }
+ if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb;
+ }
+ return true;
+}
+
+static bool parseGrayMatrix(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr)
+{
+ QColorVector whitePoint;
+ if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint))
+ return false;
+ if (!whitePoint.isValid() || !qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z + whitePoint.x) == 0.0f) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized";
+ return false;
+ }
+ colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
+ colorspaceDPtr->whitePoint = whitePoint;
+ return true;
+}
+
+static bool parseChad(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorspaceDPtr)
+{
+ if (tagEntry.size < sizeof(Sf32TagData) || qsizetype(tagEntry.size) > data.size())
+ return false;
+ const Sf32TagData chadtag = qFromUnaligned<Sf32TagData>(data.constData() + tagEntry.offset);
+ if (chadtag.type != uint32_t(Tag::sf32)) {
+ qCWarning(lcIcc, "fromIccProfile: bad chad data type");
+ return false;
+ }
+ QColorMatrix chad;
+ chad.r.x = fromFixedS1516(chadtag.value[0]);
+ chad.g.x = fromFixedS1516(chadtag.value[1]);
+ chad.b.x = fromFixedS1516(chadtag.value[2]);
+ chad.r.y = fromFixedS1516(chadtag.value[3]);
+ chad.g.y = fromFixedS1516(chadtag.value[4]);
+ chad.b.y = fromFixedS1516(chadtag.value[5]);
+ chad.r.z = fromFixedS1516(chadtag.value[6]);
+ chad.g.z = fromFixedS1516(chadtag.value[7]);
+ chad.b.z = fromFixedS1516(chadtag.value[8]);
+
+ if (!chad.isValid()) {
+ qCWarning(lcIcc, "fromIccProfile: invalid chad matrix");
+ return false;
+ }
+ colorspaceDPtr->chad = chad;
+ return true;
+}
+
+static bool parseTRCs(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr, bool isColorSpaceTypeGray)
+{
TagEntry rTrc;
TagEntry gTrc;
TagEntry bTrc;
- if (header->inputColorSpace == uint(ColorSpaceType::Gray)) {
+ if (isColorSpaceTypeGray) {
rTrc = tagIndex[Tag::kTRC];
gTrc = tagIndex[Tag::kTRC];
bTrc = tagIndex[Tag::kTRC];
@@ -766,30 +1207,30 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
QColorTrc rCurve;
QColorTrc gCurve;
QColorTrc bCurve;
- if (!parseTRC(data, rTrc, rCurve)) {
+ if (!parseTRC(QByteArrayView(data).sliced(rTrc.offset, rTrc.size), rCurve, QColorTransferTable::TwoWay)) {
qCWarning(lcIcc) << "fromIccProfile: Invalid rTRC";
return false;
}
- if (!parseTRC(data, gTrc, gCurve)) {
+ if (!parseTRC(QByteArrayView(data).sliced(gTrc.offset, gTrc.size), gCurve, QColorTransferTable::TwoWay)) {
qCWarning(lcIcc) << "fromIccProfile: Invalid gTRC";
return false;
}
- if (!parseTRC(data, bTrc, bCurve)) {
+ if (!parseTRC(QByteArrayView(data).sliced(bTrc.offset, bTrc.size), bCurve, QColorTransferTable::TwoWay)) {
qCWarning(lcIcc) << "fromIccProfile: Invalid bTRC";
return false;
}
- if (rCurve == gCurve && gCurve == bCurve && rCurve.m_type == QColorTrc::Type::Function) {
- if (rCurve.m_fun.isLinear()) {
+ if (rCurve == gCurve && gCurve == bCurve) {
+ if (rCurve.isIdentity()) {
qCDebug(lcIcc) << "fromIccProfile: Linear gamma detected";
colorspaceDPtr->trc[0] = QColorTransferFunction();
colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Linear;
colorspaceDPtr->gamma = 1.0f;
- } else if (rCurve.m_fun.isGamma()) {
+ } else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isGamma()) {
qCDebug(lcIcc) << "fromIccProfile: Simple gamma detected";
colorspaceDPtr->trc[0] = QColorTransferFunction::fromGamma(rCurve.m_fun.m_g);
colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Gamma;
colorspaceDPtr->gamma = rCurve.m_fun.m_g;
- } else if (rCurve.m_fun.isSRgb()) {
+ } else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isSRgb()) {
qCDebug(lcIcc) << "fromIccProfile: sRGB gamma detected";
colorspaceDPtr->trc[0] = QColorTransferFunction::fromSRgb();
colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::SRgb;
@@ -797,7 +1238,6 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
colorspaceDPtr->trc[0] = rCurve;
colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
}
-
colorspaceDPtr->trc[1] = colorspaceDPtr->trc[0];
colorspaceDPtr->trc[2] = colorspaceDPtr->trc[0];
} else {
@@ -806,9 +1246,151 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
colorspaceDPtr->trc[2] = bCurve;
colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
}
+ return true;
+}
+
+bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
+{
+ if (data.size() < qsizetype(sizeof(ICCProfileHeader))) {
+ qCWarning(lcIcc) << "fromIccProfile: failed size sanity 1";
+ return false;
+ }
+ 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() || qsizetype(header.profileSize) < qsizetype(sizeof(ICCProfileHeader))) {
+ qCWarning(lcIcc) << "fromIccProfile: failed size sanity 2";
+ return false;
+ }
+
+ const qsizetype offsetToData = sizeof(ICCProfileHeader) + header.tagCount * sizeof(TagTableEntry);
+ Q_ASSERT(offsetToData > 0);
+ if (offsetToData > data.size()) {
+ qCWarning(lcIcc) << "fromIccProfile: failed index size sanity";
+ return false;
+ }
+
+ QHash<Tag, TagEntry> tagIndex;
+ for (uint i = 0; i < header.tagCount; ++i) {
+ // Read tag index
+ const qsizetype tableOffset = sizeof(ICCProfileHeader) + i * sizeof(TagTableEntry);
+ const TagTableEntry tagTable = qFromUnaligned<TagTableEntry>(data.constData()
+ + tableOffset);
+
+ // Sanity check tag sizes and offsets:
+ if (qsizetype(tagTable.offset) < offsetToData) {
+ qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 1";
+ return false;
+ }
+ // Checked separately from (+ size) to handle overflow.
+ if (tagTable.offset > header.profileSize) {
+ qCWarning(lcIcc) << "fromIccProfile: failed tag offset sanity 2";
+ return false;
+ }
+ if (tagTable.size < 12) {
+ qCWarning(lcIcc) << "fromIccProfile: failed minimal tag size sanity";
+ return false;
+ }
+ if (tagTable.size > header.profileSize - tagTable.offset) {
+ qCWarning(lcIcc) << "fromIccProfile: failed tag offset + size sanity";
+ return false;
+ }
+ if (tagTable.offset & 0x03) {
+ qCWarning(lcIcc) << "fromIccProfile: invalid tag offset alignment";
+ return false;
+ }
+// printf("'%4s' %d %d\n", (const char *)&tagTable.signature,
+// quint32(tagTable.offset),
+// quint32(tagTable.size));
+ tagIndex.insert(Tag(quint32(tagTable.signature)), { tagTable.offset, tagTable.size });
+ }
+
+ bool threeComponentMatrix = true;
+
+ if (header.inputColorSpace == uint(ColorSpaceType::Rgb)) {
+ // Check the profile is three-component matrix based:
+ 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) || header.pcs == uint(Tag::Lab_)) {
+ threeComponentMatrix = false;
+ // Check if the profile is valid n-LUT based:
+ if (!tagIndex.contains(Tag::A2B0)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - neither valid three component nor n-LUT";
+ return false;
+ }
+ }
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Gray)) {
+ if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - not valid gray scale based";
+ return false;
+ }
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Cmyk)) {
+ threeComponentMatrix = false;
+ if (!tagIndex.contains(Tag::A2B0)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - CMYK, not n-LUT";
+ return false;
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ colorSpace->detach();
+ QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::get(*colorSpace);
+
+ if (threeComponentMatrix) {
+ colorspaceDPtr->isPcsLab = false;
+ colorspaceDPtr->transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
+
+ if (header.inputColorSpace == uint(ColorSpaceType::Rgb)) {
+ if (!parseRgbMatrix(data, tagIndex, colorspaceDPtr))
+ return false;
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Rgb;
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Gray)) {
+ if (!parseGrayMatrix(data, tagIndex, colorspaceDPtr))
+ return false;
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Gray;
+ } else {
+ Q_UNREACHABLE();
+ }
+ if (auto it = tagIndex.constFind(Tag::chad); it != tagIndex.constEnd()) {
+ if (!parseChad(data, it.value(), colorspaceDPtr))
+ return false;
+ } else {
+ colorspaceDPtr->chad = QColorMatrix::chromaticAdaptation(colorspaceDPtr->whitePoint);
+ }
+ if (colorspaceDPtr->colorModel == QColorSpace::ColorModel::Gray)
+ colorspaceDPtr->toXyz = colorspaceDPtr->chad;
+
+ // Reset the matrix to our canonical values:
+ if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom)
+ colorspaceDPtr->setToXyzMatrix();
+
+ if (!parseTRCs(data, tagIndex, colorspaceDPtr, header.inputColorSpace == uint(ColorSpaceType::Gray)))
+ return false;
+ } else {
+ colorspaceDPtr->isPcsLab = (header.pcs == uint(Tag::Lab_));
+ colorspaceDPtr->transformModel = QColorSpace::TransformModel::ElementListProcessing;
+ if (header.inputColorSpace == uint(ColorSpaceType::Cmyk))
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Cmyk;
+ else
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Rgb;
+
+ // Only parse the default perceptual transform for now
+ if (!parseA2B(data, tagIndex[Tag::A2B0], colorspaceDPtr, true))
+ return false;
+ if (auto it = tagIndex.constFind(Tag::B2A0); it != tagIndex.constEnd()) {
+ if (!parseA2B(data, it.value(), colorspaceDPtr, false))
+ return false;
+ }
+
+ if (auto it = tagIndex.constFind(Tag::wtpt); it != tagIndex.constEnd()) {
+ if (!parseXyzData(data, it.value(), colorspaceDPtr->whitePoint))
+ return false;
+ }
+ }
- if (tagIndex.contains(Tag::desc)) {
- if (!parseDesc(data, tagIndex[Tag::desc], colorspaceDPtr->description))
+ if (auto it = tagIndex.constFind(Tag::desc); it != tagIndex.constEnd()) {
+ if (!parseDesc(data, it.value(), colorspaceDPtr->description))
qCWarning(lcIcc) << "fromIccProfile: Failed to parse description";
else
qCDebug(lcIcc) << "fromIccProfile: Description" << colorspaceDPtr->description;
@@ -820,6 +1402,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
colorspaceDPtr->iccProfile = data;
+ Q_ASSERT(colorspaceDPtr->isValid());
return true;
}
diff --git a/src/gui/painting/qicc_p.h b/src/gui/painting/qicc_p.h
index 2a4658b84b..fd9b53b045 100644
--- a/src/gui/painting/qicc_p.h
+++ b/src/gui/painting/qicc_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QICC_P_H
#define QICC_P_H
@@ -53,6 +17,7 @@
#include <QtCore/qbytearray.h>
#include <QtGui/qtguiglobal.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qimageeffects.cpp b/src/gui/painting/qimageeffects.cpp
new file mode 100644
index 0000000000..7c2b947e08
--- /dev/null
+++ b/src/gui/painting/qimageeffects.cpp
@@ -0,0 +1,327 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qmath.h"
+#include "qdrawhelper_p.h"
+#include "qmemrotate_p.h"
+#include "qpainter.h"
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+template <int shift>
+inline int qt_static_shift(int value)
+{
+ if (shift == 0)
+ return value;
+ else if (shift > 0)
+ return value << (uint(shift) & 0x1f);
+ else
+ return value >> (uint(-shift) & 0x1f);
+}
+
+template<int aprec, int zprec>
+inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
+{
+ QRgb *pixel = (QRgb *)bptr;
+
+#define Z_MASK (0xff << zprec)
+ const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
+ const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
+ const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
+ const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
+#undef Z_MASK
+
+ const int zR_zprec = zR >> aprec;
+ const int zG_zprec = zG >> aprec;
+ const int zB_zprec = zB >> aprec;
+ const int zA_zprec = zA >> aprec;
+
+ zR += alpha * (R_zprec - zR_zprec);
+ zG += alpha * (G_zprec - zG_zprec);
+ zB += alpha * (B_zprec - zB_zprec);
+ zA += alpha * (A_zprec - zA_zprec);
+
+#define ZA_MASK (0xff << (zprec + aprec))
+ *pixel =
+ qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
+ | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
+ | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
+ | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
+#undef ZA_MASK
+}
+
+const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
+
+template<int aprec, int zprec>
+inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
+{
+ const int A_zprec = int(*(bptr)) << zprec;
+ const int z_zprec = z >> aprec;
+ z += alpha * (A_zprec - z_zprec);
+ *(bptr) = z >> (zprec + aprec);
+}
+
+template<int aprec, int zprec, bool alphaOnly>
+inline void qt_blurrow(QImage & im, int line, int alpha)
+{
+ uchar *bptr = im.scanLine(line);
+
+ int zR = 0, zG = 0, zB = 0, zA = 0;
+
+ if (alphaOnly && im.format() != QImage::Format_Indexed8)
+ bptr += alphaIndex;
+
+ const int stride = im.depth() >> 3;
+ const int im_width = im.width();
+ for (int index = 0; index < im_width; ++index) {
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ bptr += stride;
+ }
+
+ bptr -= stride;
+
+ for (int index = im_width - 2; index >= 0; --index) {
+ bptr -= stride;
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ }
+}
+
+/*
+* expblur(QImage &img, int radius)
+*
+* Based on exponential blur algorithm by Jani Huhtanen
+*
+* In-place blur of image 'img' with kernel
+* of approximate radius 'radius'.
+*
+* Blurs with two sided exponential impulse
+* response.
+*
+* aprec = precision of alpha parameter
+* in fixed-point format 0.aprec
+*
+* zprec = precision of state parameters
+* zR,zG,zB and zA in fp format 8.zprec
+*/
+template <int aprec, int zprec, bool alphaOnly>
+void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
+{
+ // halve the radius if we're using two passes
+ if (improvedQuality)
+ radius *= qreal(0.5);
+
+ Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
+ || img.format() == QImage::Format_RGB32
+ || img.format() == QImage::Format_Indexed8
+ || img.format() == QImage::Format_Grayscale8);
+
+ // choose the alpha such that pixels at radius distance from a fully
+ // saturated pixel will have an alpha component of no greater than
+ // the cutOffIntensity
+ const qreal cutOffIntensity = 2;
+ int alpha = radius <= qreal(1e-5)
+ ? ((1 << aprec)-1)
+ : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
+
+ int img_height = img.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
+ }
+
+ QImage temp(img.height(), img.width(), img.format());
+ temp.setDevicePixelRatio(img.devicePixelRatio());
+ if (transposed >= 0) {
+ if (img.depth() == 8) {
+ qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ } else {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ }
+
+ img_height = temp.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
+ }
+
+ if (transposed == 0) {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint8*>(img.bits()),
+ img.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint32*>(img.bits()),
+ img.bytesPerLine());
+ }
+ } else {
+ img = temp;
+ }
+}
+
+} // namespace
+
+#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
+#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
+
+QImage qt_halfScaled(const QImage &source)
+{
+ if (source.width() < 2 || source.height() < 2)
+ return QImage();
+
+ QImage srcImage = source;
+
+ if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
+ // assumes grayscale
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine();
+ qsizetype sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
+ *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
+ }
+
+ return dest;
+ } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine();
+ qsizetype sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
+ // alpha
+ q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
+ // rgb
+ const quint16 p16_1 = (p1[2] << 8) | p1[1];
+ const quint16 p16_2 = (p1[5] << 8) | p1[4];
+ const quint16 p16_3 = (p2[2] << 8) | p2[1];
+ const quint16 p16_4 = (p2[5] << 8) | p2[4];
+ const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
+ q[1] = result & 0xff;
+ q[2] = result >> 8;
+ }
+ }
+
+ return dest;
+ } else if (source.format() != QImage::Format_ARGB32_Premultiplied
+ && source.format() != QImage::Format_RGB32)
+ {
+ srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine() >> 2;
+ qsizetype sx2 = sx << 1;
+
+ quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine() >> 2;
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const quint32 *p1 = src;
+ const quint32 *p2 = src + sx;
+ quint32 *q = dst;
+ for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
+ *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
+ }
+
+ return dest;
+}
+
+#undef AVG
+#undef AVG16
+
+Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
+{
+ if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
+ && blurImage.format() != QImage::Format_RGB32)
+ {
+ blurImage = std::move(blurImage).convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ qreal scale = 1;
+ if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
+ blurImage = qt_halfScaled(blurImage);
+ scale = 2;
+ radius *= qreal(0.5);
+ }
+
+ if (alphaOnly)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+
+ if (p) {
+ p->scale(scale, scale);
+ p->setRenderHint(QPainter::SmoothPixmapTransform);
+ p->drawImage(QRect(QPoint(0, 0), blurImage.deviceIndependentSize().toSize()), blurImage);
+ }
+}
+
+Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
+{
+ if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index aac1e20f7b..a636635fd5 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -1,51 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <private/qimagescale_p.h>
#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
#include "qimage.h"
#include "qcolor.h"
#include "qrgba64_p.h"
+#include "qrgbafloat.h"
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
-#include "qsemaphore.h"
-#include "qthreadpool.h"
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
#endif
QT_BEGIN_NAMESPACE
@@ -307,8 +274,8 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
- QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
@@ -322,6 +289,8 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
semaphore.acquire(segments);
return;
}
+#else
+ Q_UNUSED(isi);
#endif
scaleSection(0, dh);
}
@@ -787,6 +756,221 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
}
#endif
+#if QT_CONFIG(raster_fp)
+static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow);
+
+static void qt_qimageScaleRgbaFP_up_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgbaFloat32 *sptr = ypoints[y];
+ QRgbaFloat32 *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const QRgbaFloat32 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels_rgba32f(pix, pix + sow, xap * 256, yap * 256);
+ else
+ *dptr = interpolate_rgba32f(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const QRgbaFloat32 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_rgba32f(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+void qt_qimageScaleRgbaFP(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow)
+{
+ if (isi->xup_yup == 3)
+ qt_qimageScaleRgbaFP_up_xy(isi, dest, dw, dh, dow, sow);
+ else if (isi->xup_yup == 1)
+ qt_qimageScaleRgbaFP_up_x_down_y(isi, dest, dw, dh, dow, sow);
+ else if (isi->xup_yup == 2)
+ qt_qimageScaleRgbaFP_down_x_up_y(isi, dest, dw, dh, dow, sow);
+ else
+ qt_qimageScaleRgbaFP_down_xy(isi, dest, dw, dh, dow, sow);
+}
+
+inline static void qt_qimageScaleRgbaFP_helper(const QRgbaFloat32 *pix, int xyap, int Cxy, int step, float &r, float &g, float &b, float &a)
+{
+ constexpr float f = (1.0f / float(1<<14));
+ const float xyapf = xyap * f;
+ const float Cxyf = Cxy * f;
+ r = pix->red() * xyapf;
+ g = pix->green() * xyapf;
+ b = pix->blue() * xyapf;
+ a = pix->alpha() * xyapf;
+ int j;
+ for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){
+ pix += step;
+ r += pix->red() * Cxyf;
+ g += pix->green() * Cxyf;
+ b += pix->blue() * Cxyf;
+ a += pix->alpha() * Cxyf;
+ }
+ pix += step;
+ const float jf = j * f;
+ r += pix->red() * jf;
+ g += pix->green() * jf;
+ b += pix->blue() * jf;
+ a += pix->alpha() * jf;
+}
+
+static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgbaFloat32 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
+ float r, g, b, a;
+ qt_qimageScaleRgbaFP_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ float xapf = xap * (1.f / 256.f);
+ if (xap > 0) {
+ float rr, gg, bb, aa;
+ qt_qimageScaleRgbaFP_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = (r * (1.0f - xapf) + (rr * xapf));
+ g = (g * (1.0f - xapf) + (gg * xapf));
+ b = (b * (1.0f - xapf) + (bb * xapf));
+ a = (a * (1.0f - xapf) + (aa * xapf));
+ }
+ *dptr++ = QRgbaFloat32{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgbaFloat32 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
+ float r, g, b, a;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ float yapf = yap * (1.f / 256.f);
+ if (yap > 0) {
+ float rr, gg, bb, aa;
+ qt_qimageScaleRgbaFP_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = (r * (1.0f - yapf) + (rr * yapf));
+ g = (g * (1.0f - yapf) + (gg * yapf));
+ b = (b * (1.0f - yapf) + (bb * yapf));
+ a = (a * (1.0f - yapf) + (aa * yapf));
+ }
+ *dptr++ = QRgbaFloat32{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+
+static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
+ int dw, int dh, int dow, int sow)
+{
+ const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
+ int *xpoints = isi->xpoints;
+ int *xapoints = isi->xapoints;
+ int *yapoints = isi->yapoints;
+
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ constexpr float f = 1.f / float(1 << 14);
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgbaFloat32 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
+ float rx, gx, bx, ax;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+
+ const float yapf = yap * f;
+ const float Cyf = Cy * f;
+ float r = rx * yapf;
+ float g = gx * yapf;
+ float b = bx * yapf;
+ float a = ax * yapf;
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += rx * Cyf;
+ g += gx * Cyf;
+ b += bx * Cyf;
+ a += ax * Cyf;
+ }
+ sptr += sow;
+ qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ const float jf = j * f;
+ r += rx * jf;
+ g += gx * jf;
+ b += bx * jf;
+ a += ax * jf;
+
+ *dptr++ = QRgbaFloat32{r, g, b, a};
+ }
+ }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+#endif
+
static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
int dw, int dh, int dow, int sow);
@@ -1012,6 +1196,12 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
return QImage();
}
+#if QT_CONFIG(raster_fp)
+ if (qt_fpColorPrecision(src.format()))
+ qt_qimageScaleRgbaFP(scaleinfo, (QRgbaFloat32 *)buffer.scanLine(0),
+ dw, dh, dw, src.bytesPerLine() / 16);
+ else
+#endif
#if QT_CONFIG(raster_64bit)
if (src.depth() > 32)
qt_qimageScaleRgba64(scaleinfo, (QRgba64 *)buffer.scanLine(0),
diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp
index 046e56b419..074b819862 100644
--- a/src/gui/painting/qimagescale_neon.cpp
+++ b/src/gui/painting/qimagescale_neon.cpp
@@ -1,49 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qimagescale_p.h"
#include "qimage.h"
#include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
-#include "qsemaphore.h"
-#include "qthreadpool.h"
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
#endif
#if defined(__ARM_NEON__)
@@ -58,8 +23,8 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
- QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h
index a9a4c0f858..d297443091 100644
--- a/src/gui/painting/qimagescale_p.h
+++ b/src/gui/painting/qimagescale_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QIMAGESCALE_P_H
#define QIMAGESCALE_P_H
@@ -51,6 +15,7 @@
//
#include <qimage.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp
index 70cfa08d95..982e533a32 100644
--- a/src/gui/painting/qimagescale_sse4.cpp
+++ b/src/gui/painting/qimagescale_sse4.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qimagescale_p.h"
#include "qimage.h"
@@ -43,8 +7,9 @@
#include <private/qsimd_p.h>
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
-#include "qsemaphore.h"
-#include "qthreadpool.h"
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
#endif
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
@@ -59,8 +24,8 @@ static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, con
#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
segments = std::min(segments, dh);
- QThreadPool *threadPool = QThreadPool::globalInstance();
- if (segments > 1 && !threadPool->contains(QThread::currentThread())) {
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
QSemaphore semaphore;
int y = 0;
for (int i = 0; i < segments; ++i) {
diff --git a/src/gui/painting/qmath_p.h b/src/gui/painting/qmath_p.h
index 7cc3612113..d4e5be8339 100644
--- a/src/gui/painting/qmath_p.h
+++ b/src/gui/painting/qmath_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMATH_P_H
#define QMATH_P_H
@@ -52,12 +16,28 @@
//
#include <qmath.h>
+#include <private/qglobal_p.h>
+#include <qtransform.h>
QT_BEGIN_NAMESPACE
static const qreal Q_PI = qreal(M_PI); // pi
static const qreal Q_MM_PER_INCH = 25.4;
+inline QRect qt_mapFillRect(const QRectF &rect, const QTransform &xf)
+{
+ // Only for xf <= scaling or 90 degree rotations
+ Q_ASSERT(xf.type() <= QTransform::TxScale
+ || (xf.type() == QTransform::TxRotate && qFuzzyIsNull(xf.m11()) && qFuzzyIsNull(xf.m22())));
+ // Transform the corners instead of the rect to avoid hitting numerical accuracy limit
+ // when transforming topleft and size separately and adding afterwards,
+ // as that can sometimes be slightly off around the .5 point, leading to wrong rounding
+ QPoint pt1 = xf.map(rect.topLeft()).toPoint();
+ QPoint pt2 = xf.map(rect.bottomRight()).toPoint();
+ // Normalize and adjust for the QRect vs. QRectF bottomright
+ return QRect::span(pt1, pt2).adjusted(0, 0, -1, -1);
+}
+
QT_END_NAMESPACE
#endif // QMATH_P_H
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 5c04bcb795..9752069931 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmemrotate_p.h"
#include "qpixellayout_p.h"
@@ -44,12 +8,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 +66,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 +94,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 +152,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;
@@ -226,30 +188,19 @@ inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, i
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
// packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
- if (sizeof(quint32) % sizeof(T) == 0)
- qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
- else
-#endif
+ static_assert(sizeof(quint32) % sizeof(T) == 0);
+ qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#else
qt_memrotate90_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#endif
}
-template <>
-inline void qt_memrotate90_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
-{
- // packed algorithm doesn't have any benefit for quint32
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
-
-template <>
-inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *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)
{
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
-template <class T>
-static
-inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
-{
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);
@@ -268,24 +219,11 @@ inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight,
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
// packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
- if (sizeof(quint32) % sizeof(T) == 0)
- qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
- else
-#endif
+ static_assert(sizeof(quint32) % sizeof(T) == 0);
+ qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#else
qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-}
-
-template <>
-inline void qt_memrotate270_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
-{
- // packed algorithm doesn't have any benefit for quint32
- qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
-
-template <>
-inline void qt_memrotate270_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
-{
- qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
+#endif
}
#define QT_IMPL_MEMROTATE(type) \
@@ -322,10 +260,11 @@ Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride); \
}
-QT_IMPL_MEMROTATE(quint64)
-QT_IMPL_MEMROTATE(quint32)
+QT_IMPL_SIMPLE_MEMROTATE(QRgbaFloat32)
+QT_IMPL_SIMPLE_MEMROTATE(quint64)
+QT_IMPL_SIMPLE_MEMROTATE(quint32)
+QT_IMPL_SIMPLE_MEMROTATE(quint24)
QT_IMPL_MEMROTATE(quint16)
-QT_IMPL_MEMROTATE(quint24)
QT_IMPL_MEMROTATE(quint8)
void qt_memrotate90_8(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
@@ -404,6 +343,21 @@ void qt_memrotate270_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *d
qt_memrotate270((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
}
+void qt_memrotate90_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const QRgbaFloat32 *)srcPixels, w, h, sbpl, (QRgbaFloat32 *)destPixels, dbpl);
+}
+
+void qt_memrotate180_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const QRgbaFloat32 *)srcPixels, w, h, sbpl, (QRgbaFloat32 *)destPixels, dbpl);
+}
+
+void qt_memrotate270_128(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const QRgbaFloat32 *)srcPixels, w, h, sbpl, (QRgbaFloat32 *)destPixels, dbpl);
+}
+
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
// 90, 180, 270
{
@@ -415,6 +369,8 @@ MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
{ qt_memrotate90_24, qt_memrotate180_24, qt_memrotate270_24 }, // BPP24
{ qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // BPP32
{ qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP64
+ { qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP16FPx4
+ { qt_memrotate90_128, qt_memrotate180_128, qt_memrotate270_128 }, // BPP32FPx4
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h
index 1b25655b68..70711223d1 100644
--- a/src/gui/painting/qmemrotate_p.h
+++ b/src/gui/painting/qmemrotate_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QMEMROTATE_P_H
#define QMEMROTATE_P_H
diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp
index 67e450986d..2f87ff43b7 100644
--- a/src/gui/painting/qoutlinemapper.cpp
+++ b/src/gui/painting/qoutlinemapper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoutlinemapper_p.h"
@@ -73,11 +37,31 @@ static const QRectF boundingRect(const QPointF *points, int pointCount)
return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
}
+void QOutlineMapper::setClipRect(QRect clipRect)
+{
+ auto limitCoords = [](QRect r) {
+ const QRect limitRect(QPoint(-QT_RASTER_COORD_LIMIT, -QT_RASTER_COORD_LIMIT),
+ QPoint(QT_RASTER_COORD_LIMIT, QT_RASTER_COORD_LIMIT));
+ r &= limitRect;
+ r.setWidth(qMin(r.width(), QT_RASTER_COORD_LIMIT));
+ r.setHeight(qMin(r.height(), QT_RASTER_COORD_LIMIT));
+ return r;
+ };
+
+ if (clipRect != m_clip_rect) {
+ m_clip_rect = limitCoords(clipRect);
+ const int mw = 1 << 10; // margin width. No need to trigger clipping for slight overshooting
+ m_clip_trigger_rect = QRectF(limitCoords(m_clip_rect.adjusted(-mw, -mw, mw, mw)));
+ }
+}
+
void QOutlineMapper::curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep) {
#ifdef QT_DEBUG_CONVERT
printf("QOutlineMapper::curveTo() (%f, %f)\n", ep.x(), ep.y());
#endif
+ if (!m_elements.size())
+ return;
QBezier bezier = QBezier::fromPoints(m_elements.last(), cp1, cp2, ep);
bool outsideClip = false;
@@ -234,16 +218,8 @@ void QOutlineMapper::endOutline()
m_clip_rect.x(), m_clip_rect.y(), m_clip_rect.width(), m_clip_rect.height());
#endif
-
- // Check for out of dev bounds...
- const bool do_clip = !m_in_clip_elements && ((controlPointRect.left() < -QT_RASTER_COORD_LIMIT
- || controlPointRect.right() > QT_RASTER_COORD_LIMIT
- || controlPointRect.top() < -QT_RASTER_COORD_LIMIT
- || controlPointRect.bottom() > QT_RASTER_COORD_LIMIT
- || controlPointRect.width() > QT_RASTER_COORD_LIMIT
- || controlPointRect.height() > QT_RASTER_COORD_LIMIT));
-
- if (do_clip) {
+ // Avoid rasterizing outside cliprect: faster, and ensures coords < QT_RASTER_COORD_LIMIT
+ if (!m_in_clip_elements && !m_clip_trigger_rect.contains(controlPointRect)) {
clipElements(elements, elementTypes(), m_elements.size());
} else {
convertElements(elements, elementTypes(), m_elements.size());
@@ -352,7 +328,7 @@ void QOutlineMapper::clipElements(const QPointF *elements,
int element_count)
{
// We could save a bit of time by actually implementing them fully
- // instead of going through convenience functionallity, but since
+ // instead of going through convenience functionality, but since
// this part of code hardly every used, it shouldn't matter.
QScopedValueRollback<bool> in_clip_elements(m_in_clip_elements, true);
diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h
index 04a68797c2..ff2fff6bac 100644
--- a/src/gui/painting/qoutlinemapper_p.h
+++ b/src/gui/painting/qoutlinemapper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QOUTLINEMAPPER_P_H
#define QOUTLINEMAPPER_P_H
@@ -66,10 +30,13 @@
QT_BEGIN_NAMESPACE
-// This limitations comes from qgrayraster.c. Any higher and
-// rasterization of shapes will produce incorrect results.
-const int QT_RASTER_COORD_LIMIT = 32767;
-
+// These limitations comes from qrasterizer.cpp, qcosmeticstroker.cpp, and qgrayraster.c.
+// Any higher and rasterization of shapes will produce incorrect results.
+#if Q_PROCESSOR_WORDSIZE == 8
+constexpr int QT_RASTER_COORD_LIMIT = ((1<<23) - 1); // F24dot8 in qgrayraster.c
+#else
+constexpr int QT_RASTER_COORD_LIMIT = ((1<<15) - 1); // F16dot16 in qrasterizer.cpp and qcosmeticstroker.cpp
+#endif
//#define QT_DEBUG_CONVERT
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
@@ -78,7 +45,7 @@ Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale
* class QOutlineMapper
*
* Used to map between QPainterPath and the QT_FT_Outline structure used by the
- * freetype scanconvertor.
+ * freetype scanconverter.
*
* The outline mapper uses a path iterator to get points from the path,
* so that it is possible to transform the points as they are converted. The
@@ -112,6 +79,8 @@ public:
m_curve_threshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
}
+ void setClipRect(QRect clipRect);
+
void beginOutline(Qt::FillRule fillRule)
{
#ifdef QT_DEBUG_CONVERT
@@ -196,6 +165,7 @@ public:
QDataBuffer<int> m_contours;
QRect m_clip_rect;
+ QRectF m_clip_trigger_rect;
QRectF controlPointRect; // only valid after endOutline()
QT_FT_Outline m_outline;
diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp
index e6d3a38427..4dc5f035e6 100644
--- a/src/gui/painting/qpagedpaintdevice.cpp
+++ b/src/gui/painting/qpagedpaintdevice.cpp
@@ -1,87 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpagedpaintdevice_p.h"
#include <qpagedpaintdevice.h>
QT_BEGIN_NAMESPACE
-// ### Qt 6: remove when the deprecated constructor is removed
-class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate
-{
- bool setPageLayout(const QPageLayout &newPageLayout) override
- {
- m_pageLayout = newPageLayout;
- return m_pageLayout.isEquivalentTo(newPageLayout);
- }
-
- bool setPageSize(const QPageSize &pageSize) override
- {
- m_pageLayout.setPageSize(pageSize);
- return m_pageLayout.pageSize().isEquivalentTo(pageSize);
- }
-
- bool setPageOrientation(QPageLayout::Orientation orientation) override
- {
- m_pageLayout.setOrientation(orientation);
- return m_pageLayout.orientation() == orientation;
- }
-
- bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override
- {
- m_pageLayout.setUnits(units);
- m_pageLayout.setMargins(margins);
- return m_pageLayout.margins() == margins && m_pageLayout.units() == units;
- }
-
- QPageLayout pageLayout() const override
- {
- return m_pageLayout;
- }
-
- QPageLayout m_pageLayout;
-};
-
-QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate()
-{
- delete rangeCollection;
-}
+
+QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() = default;
/*!
\class QPagedPaintDevice
@@ -96,15 +22,6 @@ QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate()
QPdfWriter and QPrinter inherit from it.
*/
-/*!
- Constructs a new paged paint device.
-
- \deprecated
- */
-QPagedPaintDevice::QPagedPaintDevice()
- : d(new QDummyPagedPaintDevicePrivate)
-{
-}
/*!
\internal
@@ -133,150 +50,6 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd()
}
/*!
- \enum QPagedPaintDevice::PageSize
-
- This enum type lists the available page sizes as defined in the Postscript
- PPD standard. These values are duplicated in QPageSize and QPrinter.
-
- The defined sizes are:
-
- \value A0 841 x 1189 mm
- \value A1 594 x 841 mm
- \value A2 420 x 594 mm
- \value A3 297 x 420 mm
- \value A4 210 x 297 mm, 8.26 x 11.69 inches
- \value A5 148 x 210 mm
- \value A6 105 x 148 mm
- \value A7 74 x 105 mm
- \value A8 52 x 74 mm
- \value A9 37 x 52 mm
- \value B0 1000 x 1414 mm
- \value B1 707 x 1000 mm
- \value B2 500 x 707 mm
- \value B3 353 x 500 mm
- \value B4 250 x 353 mm
- \value B5 176 x 250 mm, 6.93 x 9.84 inches
- \value B6 125 x 176 mm
- \value B7 88 x 125 mm
- \value B8 62 x 88 mm
- \value B9 33 x 62 mm
- \value B10 31 x 44 mm
- \value C5E 163 x 229 mm
- \value Comm10E 105 x 241 mm, U.S. Common 10 Envelope
- \value DLE 110 x 220 mm
- \value Executive 7.5 x 10 inches, 190.5 x 254 mm
- \value Folio 210 x 330 mm
- \value Ledger 431.8 x 279.4 mm
- \value Legal 8.5 x 14 inches, 215.9 x 355.6 mm
- \value Letter 8.5 x 11 inches, 215.9 x 279.4 mm
- \value Tabloid 279.4 x 431.8 mm
- \value Custom Unknown, or a user defined size.
- \value A10
- \value A3Extra
- \value A4Extra
- \value A4Plus
- \value A4Small
- \value A5Extra
- \value B5Extra
- \value JisB0
- \value JisB1
- \value JisB2
- \value JisB3
- \value JisB4
- \value JisB5
- \value JisB6,
- \value JisB7
- \value JisB8
- \value JisB9
- \value JisB10
- \value AnsiA = Letter
- \value AnsiB = Ledger
- \value AnsiC
- \value AnsiD
- \value AnsiE
- \value LegalExtra
- \value LetterExtra
- \value LetterPlus
- \value LetterSmall
- \value TabloidExtra
- \value ArchA
- \value ArchB
- \value ArchC
- \value ArchD
- \value ArchE
- \value Imperial7x9
- \value Imperial8x10
- \value Imperial9x11
- \value Imperial9x12
- \value Imperial10x11
- \value Imperial10x13
- \value Imperial10x14
- \value Imperial12x11
- \value Imperial15x11
- \value ExecutiveStandard
- \value Note
- \value Quarto
- \value Statement
- \value SuperA
- \value SuperB
- \value Postcard
- \value DoublePostcard
- \value Prc16K
- \value Prc32K
- \value Prc32KBig
- \value FanFoldUS
- \value FanFoldGerman
- \value FanFoldGermanLegal
- \value EnvelopeB4
- \value EnvelopeB5
- \value EnvelopeB6
- \value EnvelopeC0
- \value EnvelopeC1
- \value EnvelopeC2
- \value EnvelopeC3
- \value EnvelopeC4
- \value EnvelopeC5 = C5E
- \value EnvelopeC6
- \value EnvelopeC65
- \value EnvelopeC7
- \value EnvelopeDL = DLE
- \value Envelope9
- \value Envelope10 = Comm10E
- \value Envelope11
- \value Envelope12
- \value Envelope14
- \value EnvelopeMonarch
- \value EnvelopePersonal
- \value EnvelopeChou3
- \value EnvelopeChou4
- \value EnvelopeInvite
- \value EnvelopeItalian
- \value EnvelopeKaku2
- \value EnvelopeKaku3
- \value EnvelopePrc1
- \value EnvelopePrc2
- \value EnvelopePrc3
- \value EnvelopePrc4
- \value EnvelopePrc5
- \value EnvelopePrc6
- \value EnvelopePrc7
- \value EnvelopePrc8
- \value EnvelopePrc9
- \value EnvelopePrc10
- \value EnvelopeYou4
- \value LastPageSize = EnvelopeYou4
- \omitvalue NPageSize
- \omitvalue NPaperSize
-
- Due to historic reasons QPageSize::Executive is not the same as the standard
- Postscript and Windows Executive size, use QPageSize::ExecutiveStandard instead.
-
- The Postscript standard size QPageSize::Folio is different to the Windows
- DMPAPER_FOLIO size, use the Postscript standard size QPageSize::FanFoldGermanLegal
- if needed.
-*/
-
-/*!
\fn bool QPagedPaintDevice::newPage()
Starts a new page. Returns \c true on success.
@@ -297,76 +70,6 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd()
*/
/*!
- Sets the size of the a page to \a size.
-
- \sa setPageSizeMM()
- */
-void QPagedPaintDevice::setPageSize(PageSize size)
-{
- d->setPageSize(QPageSize(QPageSize::PageSizeId(size)));
-}
-
-/*!
- Returns the currently used page size.
- */
-QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const
-{
- return PageSize(d->pageLayout().pageSize().id());
-}
-
-/*!
- Sets the page size to \a size. \a size is specified in millimeters.
-
- If the size matches a standard QPagedPaintDevice::PageSize then that page
- size will be used, otherwise QPagedPaintDevice::Custom will be set.
-*/
-void QPagedPaintDevice::setPageSizeMM(const QSizeF &size)
-{
- d->setPageSize(QPageSize(size, QPageSize::Millimeter));
-}
-
-/*!
- Returns the page size in millimeters.
- */
-QSizeF QPagedPaintDevice::pageSizeMM() const
-{
- return d->pageLayout().pageSize().size(QPageSize::Millimeter);
-}
-
-/*!
- Sets the margins to be used to \a margins.
-
- Margins are specified in millimeters.
-
- The margins are purely a hint to the drawing method. They don't affect the
- coordinate system or clipping.
-
- \sa margins()
- */
-void QPagedPaintDevice::setMargins(const Margins &margins)
-{
- d->setPageMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom), QPageLayout::Millimeter);
-}
-
-/*!
- Returns the current margins of the paint device. The default is 0.
-
- Margins are specified in millimeters.
-
- \sa setMargins()
- */
-QPagedPaintDevice::Margins QPagedPaintDevice::margins() const
-{
- QMarginsF margins = d->pageLayout().margins(QPageLayout::Millimeter);
- Margins result;
- result.left = margins.left();
- result.top = margins.top();
- result.right = margins.right();
- result.bottom = margins.bottom();
- return result;
-}
-
-/*!
\since 5.3
Sets the page layout to \a newPageLayout.
@@ -421,7 +124,7 @@ bool QPagedPaintDevice::setPageSize(const QPageSize &pageSize)
You should not call any painting methods between a call to setPageOrientation()
and newPage() as the wrong paint metrics may be used.
- To get the current QPageLayout::Orientation use pageLayout().pageOrientation().
+ To get the current QPageLayout::Orientation use pageLayout().orientation().
Returns true if the page orientation was successfully set to \a orientation.
@@ -436,28 +139,6 @@ bool QPagedPaintDevice::setPageOrientation(QPageLayout::Orientation orientation)
/*!
\since 5.3
- Set the page \a margins in the current page layout units.
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new margins to a new page.
- You should not call any painting methods between a call to setPageMargins()
- and newPage() as the wrong paint metrics may be used.
-
- To get the current page margins use pageLayout().pageMargins().
-
- Returns true if the page margins were successfully set to \a margins.
-
- \sa pageLayout()
-*/
-
-bool QPagedPaintDevice::setPageMargins(const QMarginsF &margins)
-{
- return setPageMargins(margins, pageLayout().units());
-}
-
-/*!
- \since 5.3
-
Set the page \a margins defined in the given \a units.
You should call this before calling QPainter::begin(), or immediately
@@ -465,7 +146,7 @@ bool QPagedPaintDevice::setPageMargins(const QMarginsF &margins)
You should not call any painting methods between a call to setPageMargins()
and newPage() as the wrong paint metrics may be used.
- To get the current page margins use pageLayout().pageMargins().
+ To get the current page margins use pageLayout().margins().
Returns true if the page margins were successfully set to \a margins.
@@ -495,32 +176,25 @@ QPageLayout QPagedPaintDevice::pageLayout() const
}
/*!
- \internal
+ \since 6.0
- \deprecated
+ Returns the page ranges associated with this device.
- Returns the internal device page layout.
+ \sa QPageRanges, QPrinter::fromPage(), QPrinter::toPage()
*/
-
-QPageLayout QPagedPaintDevice::devicePageLayout() const
+QPageRanges QPagedPaintDevice::pageRanges() const
{
- qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, just use QPagedPaintDevice::pageLayout()");
- return d->pageLayout();
+ return d->pageRanges;
}
/*!
- \internal
+ \since 6.0
- \deprecated
-
- Returns the internal device page layout.
+ Sets the page ranges for this device to \a ranges.
*/
-
-QPageLayout &QPagedPaintDevice::devicePageLayout()
+void QPagedPaintDevice::setPageRanges(const QPageRanges &ranges)
{
- qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, you shouldn't be using this at all.");
- static QPageLayout dummy;
- return dummy;
+ d->pageRanges = ranges;
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h
index 21e23e0eb4..ffe82f6555 100644
--- a/src/gui/painting/qpagedpaintdevice.h
+++ b/src/gui/painting/qpagedpaintdevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAGEDPAINTDEVICE_H
#define QPAGEDPAINTDEVICE_H
@@ -43,6 +7,7 @@
#include <QtGui/qtguiglobal.h>
#include <QtGui/qpaintdevice.h>
#include <QtGui/qpagelayout.h>
+#include <QtGui/qpageranges.h>
QT_BEGIN_NAMESPACE
@@ -55,197 +20,25 @@ class QPagedPaintDevicePrivate;
class Q_GUI_EXPORT QPagedPaintDevice : public QPaintDevice
{
public:
- QT_DEPRECATED QPagedPaintDevice();
~QPagedPaintDevice();
virtual bool newPage() = 0;
- // ### Qt6 Remove in favor of QPage::PageSize
- // NOTE: Must keep in sync with QPageSize and QPrinter
- enum PageSize {
- // Existing Qt sizes
- A4,
- B5,
- Letter,
- Legal,
- Executive,
- A0,
- A1,
- A2,
- A3,
- A5,
- A6,
- A7,
- A8,
- A9,
- B0,
- B1,
- B10,
- B2,
- B3,
- B4,
- B6,
- B7,
- B8,
- B9,
- C5E,
- Comm10E,
- DLE,
- Folio,
- Ledger,
- Tabloid,
- Custom,
-
- // New values derived from PPD standard
- A10,
- A3Extra,
- A4Extra,
- A4Plus,
- A4Small,
- A5Extra,
- B5Extra,
-
- JisB0,
- JisB1,
- JisB2,
- JisB3,
- JisB4,
- JisB5,
- JisB6,
- JisB7,
- JisB8,
- JisB9,
- JisB10,
-
- // AnsiA = Letter,
- // AnsiB = Ledger,
- AnsiC,
- AnsiD,
- AnsiE,
- LegalExtra,
- LetterExtra,
- LetterPlus,
- LetterSmall,
- TabloidExtra,
-
- ArchA,
- ArchB,
- ArchC,
- ArchD,
- ArchE,
-
- Imperial7x9,
- Imperial8x10,
- Imperial9x11,
- Imperial9x12,
- Imperial10x11,
- Imperial10x13,
- Imperial10x14,
- Imperial12x11,
- Imperial15x11,
-
- ExecutiveStandard,
- Note,
- Quarto,
- Statement,
- SuperA,
- SuperB,
- Postcard,
- DoublePostcard,
- Prc16K,
- Prc32K,
- Prc32KBig,
-
- FanFoldUS,
- FanFoldGerman,
- FanFoldGermanLegal,
-
- EnvelopeB4,
- EnvelopeB5,
- EnvelopeB6,
- EnvelopeC0,
- EnvelopeC1,
- EnvelopeC2,
- EnvelopeC3,
- EnvelopeC4,
- // EnvelopeC5 = C5E,
- EnvelopeC6,
- EnvelopeC65,
- EnvelopeC7,
- // EnvelopeDL = DLE,
-
- Envelope9,
- // Envelope10 = Comm10E,
- Envelope11,
- Envelope12,
- Envelope14,
- EnvelopeMonarch,
- EnvelopePersonal,
-
- EnvelopeChou3,
- EnvelopeChou4,
- EnvelopeInvite,
- EnvelopeItalian,
- EnvelopeKaku2,
- EnvelopeKaku3,
- EnvelopePrc1,
- EnvelopePrc2,
- EnvelopePrc3,
- EnvelopePrc4,
- EnvelopePrc5,
- EnvelopePrc6,
- EnvelopePrc7,
- EnvelopePrc8,
- EnvelopePrc9,
- EnvelopePrc10,
- EnvelopeYou4,
-
- // Last item, with commonly used synynoms from QPagedPrintEngine / QPrinter
- LastPageSize = EnvelopeYou4,
- NPageSize = LastPageSize,
- NPaperSize = LastPageSize,
-
- // Convenience overloads for naming consistency
- AnsiA = Letter,
- AnsiB = Ledger,
- EnvelopeC5 = C5E,
- EnvelopeDL = DLE,
- Envelope10 = Comm10E
- };
-
// keep in sync with QPdfEngine::PdfVersion!
enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b, PdfVersion_1_6 };
- // ### Qt6 Make these virtual
- bool setPageLayout(const QPageLayout &pageLayout);
- bool setPageSize(const QPageSize &pageSize);
- bool setPageOrientation(QPageLayout::Orientation orientation);
- bool setPageMargins(const QMarginsF &margins);
- bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units);
+ virtual bool setPageLayout(const QPageLayout &pageLayout);
+ virtual bool setPageSize(const QPageSize &pageSize);
+ virtual bool setPageOrientation(QPageLayout::Orientation orientation);
+ virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units = QPageLayout::Millimeter);
QPageLayout pageLayout() const;
- virtual void setPageSize(PageSize size);
- PageSize pageSize() const;
-
- virtual void setPageSizeMM(const QSizeF &size);
- QSizeF pageSizeMM() const;
-
- // ### Qt6 Remove in favor of QMarginsF
- struct Margins {
- qreal left;
- qreal right;
- qreal top;
- qreal bottom;
- };
-
- virtual void setMargins(const Margins &margins);
- Margins margins() const;
+ virtual void setPageRanges(const QPageRanges &ranges);
+ QPageRanges pageRanges() const;
protected:
QPagedPaintDevice(QPagedPaintDevicePrivate *dd);
QPagedPaintDevicePrivate *dd();
- QT_DEPRECATED QPageLayout devicePageLayout() const;
- QT_DEPRECATED QPageLayout &devicePageLayout();
friend class QPagedPaintDevicePrivate;
QPagedPaintDevicePrivate *d;
};
diff --git a/src/gui/painting/qpagedpaintdevice_p.h b/src/gui/painting/qpagedpaintdevice_p.h
index 1717727be4..8e2205344e 100644
--- a/src/gui/painting/qpagedpaintdevice_p.h
+++ b/src/gui/painting/qpagedpaintdevice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAGEDPAINTDEVICE_P_H
#define QPAGEDPAINTDEVICE_P_H
@@ -53,7 +17,6 @@
#include <QtGui/private/qtguiglobal_p.h>
#include <qpagedpaintdevice.h>
-#include <qrangecollection.h>
QT_BEGIN_NAMESPACE
@@ -61,8 +24,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate
{
public:
QPagedPaintDevicePrivate()
- : rangeCollection(new QRangeCollection),
- pageOrderAscending(true),
+ : pageOrderAscending(true),
printSelectionOnly(false)
{
}
@@ -83,7 +45,7 @@ public:
static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; }
// These are currently required to keep QPrinter functionality working in QTextDocument::print()
- QRangeCollection *rangeCollection;
+ QPageRanges pageRanges;
bool pageOrderAscending;
bool printSelectionOnly;
};
diff --git a/src/gui/painting/qpagelayout.cpp b/src/gui/painting/qpagelayout.cpp
index 2634a448a5..e60f464d6e 100644
--- a/src/gui/painting/qpagelayout.cpp
+++ b/src/gui/painting/qpagelayout.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpagelayout.h"
@@ -48,6 +12,10 @@
QT_BEGIN_NAMESPACE
+QT_IMPL_METATYPE_EXTERN(QPageLayout)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QPageLayout::Unit, QPageLayout__Unit)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QPageLayout::Orientation, QPageLayout__Orientation)
+
// Multiplier for converting units to points.
Q_GUI_EXPORT qreal qt_pointMultiplier(QPageLayout::Unit unit)
{
@@ -71,41 +39,19 @@ Q_GUI_EXPORT qreal qt_pointMultiplier(QPageLayout::Unit unit)
// Multiplier for converting pixels to points.
extern qreal qt_pixelMultiplier(int resolution);
-QPointF qt_convertPoint(const QPointF &xy, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
-{
- // If the size have the same units, or are all 0, then don't need to convert
- if (fromUnits == toUnits || xy.isNull())
- return xy;
-
- // If converting to points then convert and round to 0 decimal places
- if (toUnits == QPageLayout::Point) {
- const qreal multiplier = qt_pointMultiplier(fromUnits);
- return QPointF(qRound(xy.x() * multiplier),
- qRound(xy.y() * multiplier));
- }
-
- // If converting to other units, need to convert to unrounded points first
- QPointF pointXy = (fromUnits == QPageLayout::Point) ? xy : xy * qt_pointMultiplier(fromUnits);
-
- // Then convert from points to required units rounded to 2 decimal places
- const qreal multiplier = qt_pointMultiplier(toUnits);
- return QPointF(qRound(pointXy.x() * 100 / multiplier) / 100.0,
- qRound(pointXy.y() * 100 / multiplier) / 100.0);
-}
-
Q_GUI_EXPORT QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
{
// If the margins have the same units, or are all 0, then don't need to convert
if (fromUnits == toUnits || margins.isNull())
return margins;
- // If converting to points then convert and round to 0 decimal places
+ // If converting to points then convert and round up to 2 decimal places
if (toUnits == QPageLayout::Point) {
- const qreal multiplier = qt_pointMultiplier(fromUnits);
- return QMarginsF(qRound(margins.left() * multiplier),
- qRound(margins.top() * multiplier),
- qRound(margins.right() * multiplier),
- qRound(margins.bottom() * multiplier));
+ const qreal multiplierX100 = qt_pointMultiplier(fromUnits) * 100;
+ return QMarginsF(qCeil(margins.left() * multiplierX100) / 100.0,
+ qCeil(margins.top() * multiplierX100) / 100.0,
+ qCeil(margins.right() * multiplierX100) / 100.0,
+ qCeil(margins.bottom() * multiplierX100) / 100.0);
}
// If converting to other units, need to convert to unrounded points first
@@ -133,10 +79,10 @@ public:
bool isValid() const;
- void clampMargins(const QMarginsF &margins);
+ QMarginsF clampMargins(const QMarginsF &margins) const;
QMarginsF margins(QPageLayout::Unit units) const;
- QMargins marginsPoints() const;
+ QMarginsF marginsPoints() const;
QMargins marginsPixels(int resolution) const;
void setDefaultMargins(const QMarginsF &minMargins);
@@ -205,12 +151,12 @@ bool QPageLayoutPrivate::isValid() const
return m_pageSize.isValid();
}
-void QPageLayoutPrivate::clampMargins(const QMarginsF &margins)
+QMarginsF QPageLayoutPrivate::clampMargins(const QMarginsF &margins) const
{
- m_margins = QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
- qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
- qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
- qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
+ return QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
+ qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
+ qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
+ qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
}
QMarginsF QPageLayoutPrivate::margins(QPageLayout::Unit units) const
@@ -218,25 +164,25 @@ QMarginsF QPageLayoutPrivate::margins(QPageLayout::Unit units) const
return qt_convertMargins(m_margins, m_units, units);
}
-QMargins QPageLayoutPrivate::marginsPoints() const
+QMarginsF QPageLayoutPrivate::marginsPoints() const
{
- return qt_convertMargins(m_margins, m_units, QPageLayout::Point).toMargins();
+ return qt_convertMargins(m_margins, m_units, QPageLayout::Point);
}
QMargins QPageLayoutPrivate::marginsPixels(int resolution) const
{
- return marginsPoints() / qt_pixelMultiplier(resolution);
+ return QMarginsF(marginsPoints() / qt_pixelMultiplier(resolution)).toMargins();
}
void QPageLayoutPrivate::setDefaultMargins(const QMarginsF &minMargins)
{
m_minMargins = minMargins;
- m_maxMargins = QMarginsF(m_fullSize.width() - m_minMargins.right(),
- m_fullSize.height() - m_minMargins.bottom(),
- m_fullSize.width() - m_minMargins.left(),
- m_fullSize.height() - m_minMargins.top());
+ m_maxMargins = QMarginsF(qMax(m_fullSize.width() - m_minMargins.right(), qreal(0)),
+ qMax(m_fullSize.height() - m_minMargins.bottom(), qreal(0)),
+ qMax(m_fullSize.width() - m_minMargins.left(), qreal(0)),
+ qMax(m_fullSize.height() - m_minMargins.top(), qreal(0)));
if (m_mode == QPageLayout::StandardMode)
- clampMargins(m_margins);
+ m_margins = clampMargins(m_margins);
}
QSizeF QPageLayoutPrivate::fullSizeUnits(QPageLayout::Unit units) const
@@ -342,6 +288,27 @@ QRectF QPageLayoutPrivate::paintRect() const
\value StandardMode Paint Rect includes margins, margins must fall between the minimum and maximum.
\value FullPageMode Paint Rect excludes margins, margins can be any value and must be managed manually.
+
+ In StandardMode, when setting margins, use \l{QPageLayout::OutOfBoundsPolicy::}{Clamp} to
+ automatically clamp the margins to fall between the minimum and maximum
+ allowed values.
+
+ \sa OutOfBoundsPolicy
+*/
+
+/*!
+ \enum QPageLayout::OutOfBoundsPolicy
+ \since 6.8
+
+ Defines the policy for margins that are out of bounds
+
+ \value Reject The margins must fall within the minimum and maximum values,
+ otherwise they will be rejected.
+ \value Clamp The margins are clamped between the minimum and maximum
+ values to ensure they are valid.
+
+ \note The policy has no effect in \l{QPageLayout::Mode}{FullPageMode},
+ where all margins are accepted.
*/
/*!
@@ -415,7 +382,7 @@ QPageLayout &QPageLayout::operator=(const QPageLayout &other)
*/
/*!
- \relates QPageLayout
+ \fn bool QPageLayout::operator==(const QPageLayout &lhs, const QPageLayout &rhs)
Returns \c true if page layout \a lhs is equal to page layout \a rhs,
i.e. if all the attributes are exactly equal.
@@ -427,14 +394,8 @@ QPageLayout &QPageLayout::operator=(const QPageLayout &other)
\sa QPageLayout::isEquivalentTo()
*/
-bool operator==(const QPageLayout &lhs, const QPageLayout &rhs)
-{
- return lhs.d == rhs.d || *lhs.d == *rhs.d;
-}
-
/*!
- \fn bool operator!=(const QPageLayout &lhs, const QPageLayout &rhs)
- \relates QPageLayout
+ \fn bool QPageLayout::operator!=(const QPageLayout &lhs, const QPageLayout &rhs)
Returns \c true if page layout \a lhs is not equal to page layout \a rhs,
i.e. if any of the attributes differ.
@@ -447,6 +408,15 @@ bool operator==(const QPageLayout &lhs, const QPageLayout &rhs)
*/
/*!
+ \internal
+*/
+bool QPageLayout::equals(const QPageLayout &other) const
+{
+ return d == other.d || *d == *other.d;
+}
+
+
+/*!
Returns \c true if this page layout is equivalent to the \a other page layout,
i.e. if the page has the same size, margins and orientation.
*/
@@ -576,39 +546,52 @@ QPageLayout::Unit QPageLayout::units() const
}
/*!
- Sets the page margins of the page layout to \a margins
+ Sets the page margins of the page layout to \a margins.
Returns true if the margins were successfully set.
The units used are those currently defined for the layout. To use different
units then call setUnits() first.
- If in the default StandardMode then all the new margins must fall between the
- minimum margins set and the maximum margins allowed by the page size,
- otherwise the margins will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa margins(), units()
*/
-bool QPageLayout::setMargins(const QMarginsF &margins)
+bool QPageLayout::setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy)
{
if (d->m_mode == FullPageMode) {
- d.detach();
- d->m_margins = margins;
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
return true;
- } else if (margins.left() >= d->m_minMargins.left()
- && margins.right() >= d->m_minMargins.right()
- && margins.top() >= d->m_minMargins.top()
- && margins.bottom() >= d->m_minMargins.bottom()
- && margins.left() <= d->m_maxMargins.left()
- && margins.right() <= d->m_maxMargins.right()
- && margins.top() <= d->m_maxMargins.top()
- && margins.bottom() <= d->m_maxMargins.bottom()) {
- d.detach();
- d->m_margins = margins;
+ }
+
+ if (outOfBoundsPolicy == OutOfBoundsPolicy::Clamp) {
+ const QMarginsF clampedMargins = d->clampMargins(margins);
+ if (clampedMargins != d->m_margins) {
+ d.detach();
+ d->m_margins = clampedMargins;
+ }
return true;
}
+
+ if (margins.left() >= d->m_minMargins.left()
+ && margins.right() >= d->m_minMargins.right()
+ && margins.top() >= d->m_minMargins.top()
+ && margins.bottom() >= d->m_minMargins.bottom()
+ && margins.left() <= d->m_maxMargins.left()
+ && margins.right() <= d->m_maxMargins.right()
+ && margins.top() <= d->m_maxMargins.top()
+ && margins.bottom() <= d->m_maxMargins.bottom()) {
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
+ return true;
+ }
+
return false;
}
@@ -619,23 +602,27 @@ bool QPageLayout::setMargins(const QMarginsF &margins)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setLeftMargin(qreal leftMargin)
+bool QPageLayout::setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ leftMargin = qBound(d->m_minMargins.left(), leftMargin, d->m_maxMargins.left());
+
+ if (qFuzzyCompare(leftMargin, d->m_margins.left()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (leftMargin >= d->m_minMargins.left() && leftMargin <= d->m_maxMargins.left())) {
d.detach();
d->m_margins.setLeft(leftMargin);
return true;
}
+
return false;
}
@@ -646,23 +633,27 @@ bool QPageLayout::setLeftMargin(qreal leftMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setRightMargin(qreal rightMargin)
+bool QPageLayout::setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ rightMargin = qBound(d->m_minMargins.right(), rightMargin, d->m_maxMargins.right());
+
+ if (qFuzzyCompare(rightMargin, d->m_margins.right()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (rightMargin >= d->m_minMargins.right() && rightMargin <= d->m_maxMargins.right())) {
d.detach();
d->m_margins.setRight(rightMargin);
return true;
}
+
return false;
}
@@ -673,23 +664,27 @@ bool QPageLayout::setRightMargin(qreal rightMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setTopMargin(qreal topMargin)
+bool QPageLayout::setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ topMargin = qBound(d->m_minMargins.top(), topMargin, d->m_maxMargins.top());
+
+ if (qFuzzyCompare(topMargin, d->m_margins.top()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (topMargin >= d->m_minMargins.top() && topMargin <= d->m_maxMargins.top())) {
d.detach();
d->m_margins.setTop(topMargin);
return true;
}
+
return false;
}
@@ -700,23 +695,27 @@ bool QPageLayout::setTopMargin(qreal topMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setBottomMargin(qreal bottomMargin)
+bool QPageLayout::setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ bottomMargin = qBound(d->m_minMargins.bottom(), bottomMargin, d->m_maxMargins.bottom());
+
+ if (qFuzzyCompare(bottomMargin, d->m_margins.bottom()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (bottomMargin >= d->m_minMargins.bottom() && bottomMargin <= d->m_maxMargins.bottom())) {
d.detach();
d->m_margins.setBottom(bottomMargin);
return true;
}
+
return false;
}
@@ -750,7 +749,7 @@ QMarginsF QPageLayout::margins(Unit units) const
QMargins QPageLayout::marginsPoints() const
{
- return d->marginsPoints();
+ return d->marginsPoints().toMargins();
}
/*!
@@ -917,7 +916,7 @@ QRect QPageLayout::paintRectPoints() const
if (!isValid())
return QRect();
return d->m_mode == FullPageMode ? d->fullRectPoints()
- : d->fullRectPoints() - d->marginsPoints();
+ : d->fullRectPoints() - d->marginsPoints().toMargins();
}
/*!
diff --git a/src/gui/painting/qpagelayout.h b/src/gui/painting/qpagelayout.h
index 7ee0ce7a76..1e340b6d75 100644
--- a/src/gui/painting/qpagelayout.h
+++ b/src/gui/painting/qpagelayout.h
@@ -1,47 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAGELAYOUT_H
#define QPAGELAYOUT_H
#include <QtGui/qtguiglobal.h>
-#include <QtCore/qsharedpointer.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
#include <QtCore/qmargins.h>
@@ -66,7 +30,6 @@ public:
Cicero
};
- // NOTE: Must keep in sync with QPrinter::Orientation
enum Orientation {
Portrait,
Landscape
@@ -77,18 +40,22 @@ public:
FullPageMode // Paint Rect excludes margins
};
+ enum class OutOfBoundsPolicy {
+ Reject,
+ Clamp
+ };
+
QPageLayout();
QPageLayout(const QPageSize &pageSize, Orientation orientation,
const QMarginsF &margins, Unit units = Point,
const QMarginsF &minMargins = QMarginsF(0, 0, 0, 0));
QPageLayout(const QPageLayout &other);
- QPageLayout &operator=(QPageLayout &&other) noexcept { swap(other); return *this; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPageLayout)
QPageLayout &operator=(const QPageLayout &other);
~QPageLayout();
- void swap(QPageLayout &other) noexcept { qSwap(d, other.d); }
+ void swap(QPageLayout &other) noexcept { d.swap(other.d); }
- friend Q_GUI_EXPORT bool operator==(const QPageLayout &lhs, const QPageLayout &rhs);
bool isEquivalentTo(const QPageLayout &other) const;
bool isValid() const;
@@ -106,11 +73,19 @@ public:
void setUnits(Unit units);
Unit units() const;
+#if QT_GUI_REMOVED_SINCE(6, 8)
bool setMargins(const QMarginsF &margins);
bool setLeftMargin(qreal leftMargin);
bool setRightMargin(qreal rightMargin);
bool setTopMargin(qreal topMargin);
bool setBottomMargin(qreal bottomMargin);
+#endif
+
+ bool setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
QMarginsF margins() const;
QMarginsF margins(Unit units) const;
@@ -133,23 +108,26 @@ public:
private:
friend class QPageLayoutPrivate;
+ bool equals(const QPageLayout &other) const;
+
+ friend inline bool operator==(const QPageLayout &lhs, const QPageLayout &rhs)
+ { return lhs.equals(rhs); }
+ friend inline bool operator!=(const QPageLayout &lhs, const QPageLayout &rhs)
+ { return !lhs.equals(rhs); }
+
QExplicitlySharedDataPointer<QPageLayoutPrivate> d;
};
Q_DECLARE_SHARED(QPageLayout)
-Q_GUI_EXPORT bool operator==(const QPageLayout &lhs, const QPageLayout &rhs);
-inline bool operator!=(const QPageLayout &lhs, const QPageLayout &rhs)
-{ return !operator==(lhs, rhs); }
-
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QPageLayout &pageLayout);
#endif
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QPageLayout)
-Q_DECLARE_METATYPE(QPageLayout::Unit)
-Q_DECLARE_METATYPE(QPageLayout::Orientation)
+QT_DECL_METATYPE_EXTERN(QPageLayout, Q_GUI_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QPageLayout::Unit, QPageLayout__Unit, Q_GUI_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QPageLayout::Orientation, QPageLayout__Orientation, Q_GUI_EXPORT)
#endif // QPAGELAYOUT_H
diff --git a/src/gui/painting/qpageranges.cpp b/src/gui/painting/qpageranges.cpp
new file mode 100644
index 0000000000..99a0009883
--- /dev/null
+++ b/src/gui/painting/qpageranges.cpp
@@ -0,0 +1,367 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qpageranges.h"
+#include "qpageranges_p.h"
+
+#include <QtCore/qstack.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_IMPL_METATYPE_EXTERN(QPageRanges)
+
+void QPageRangesPrivate::mergeIntervals()
+{
+ const int count = intervals.size();
+
+ if (count <= 1)
+ return;
+
+ std::sort(intervals.begin(), intervals.end());
+
+ QStack<QPageRanges::Range> stack;
+ stack.push(intervals[0]);
+
+ for (int i = 1; i < count; ++i) {
+ QPageRanges::Range &top = stack.top();
+
+ if (top.to < intervals[i].from - 1)
+ stack.push(intervals[i]);
+ else if (top.to < intervals[i].to)
+ top.to = intervals[i].to;
+ }
+
+ intervals = stack;
+}
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPageRangesPrivate)
+
+/*!
+ \class QPageRanges
+ \brief The QPageRanges class represents a collection of page ranges.
+ \inmodule QtGui
+ \ingroup painting
+ \ingroup printing
+ \ingroup shared
+ \since 6.0
+
+ Use QPagedPaintDevice::pageRanges() to access the collection of page ranges
+ associated with a paged device.
+*/
+
+/*!
+ Constructs an empty QPageRanges object.
+*/
+QPageRanges::QPageRanges() = default;
+
+/*!
+ Constructs a QPageRanges object by copying \a other.
+*/
+QPageRanges::QPageRanges(const QPageRanges &other) noexcept = default;
+
+/*!
+ \fn QPageRanges::QPageRanges(QPageRanges &&other)
+
+ Constructs a QPageRanges object by moving from \a other.
+*/
+
+/*!
+ Destroys the page ranges.
+*/
+QPageRanges::~QPageRanges() = default;
+
+/*!
+ Assigns \a other to this QPageRanges object.
+*/
+QPageRanges &QPageRanges::operator=(const QPageRanges &other) noexcept = default;
+
+/*!
+ \fn QPageRanges &QPageRanges::operator=(QPageRanges &&other)
+ Moves \a other into this QPageRanges object.
+*/
+
+/*!
+ Adds the single page \a pageNumber to the ranges.
+
+ \note Page numbers start with 1. Attempts to add page numbers
+ smaller than 1 will be ignored with a warning.
+*/
+void QPageRanges::addPage(int pageNumber)
+{
+ if (pageNumber <= 0) {
+ qWarning("QPageRanges::addPage: 'pageNumber' must be greater than 0");
+ return;
+ }
+
+ detach();
+ d->intervals.append({ pageNumber, pageNumber });
+ d->mergeIntervals();
+}
+
+/*!
+ Adds the range specified with \a from and \a to to the ranges.
+
+ \note Page numbers start with 1. Attempts to add page numbers
+ smaller than 1 will be ignored with a warning.
+*/
+void QPageRanges::addRange(int from, int to)
+{
+ if (from <= 0 || to <= 0) {
+ qWarning("QPageRanges::addRange: 'from' and 'to' must be greater than 0");
+ return;
+ }
+ if (to < from)
+ std::swap(from, to);
+
+ detach();
+ d->intervals.append({from, to});
+ d->mergeIntervals();
+}
+
+/*!
+ Returns a list with the values of the ranges.
+*/
+QList<QPageRanges::Range> QPageRanges::toRangeList() const
+{
+ if (d)
+ return d->intervals;
+ return QList<QPageRanges::Range>{};
+}
+
+/*!
+ Removes all page ranges.
+*/
+void QPageRanges::clear()
+{
+ d.reset();
+}
+
+/*!
+ Constructs and returns a QPageRanges object populated with the
+ \a ranges from the string representation.
+
+ \code
+ QPrinter printer;
+ QPageRanges ranges = QPageRanges::fromString("1-3,6-7");
+ printer.setPageRanges(ranges);
+ \endcode
+
+ In case of parsing error, returns an empty QPageRanges object.
+
+ \sa isEmpty()
+*/
+QPageRanges QPageRanges::fromString(const QString &ranges)
+{
+ QList<Range> intervals;
+ const QStringList items = ranges.split(u',');
+ for (const QString &item : items) {
+ if (item.isEmpty())
+ return QPageRanges();
+
+ if (item.contains(u'-')) {
+ const QStringList rangeItems = item.split(u'-');
+ if (rangeItems.size() != 2)
+ return QPageRanges();
+
+ bool ok;
+ const int number1 = rangeItems[0].toInt(&ok);
+ if (!ok)
+ return QPageRanges();
+
+ const int number2 = rangeItems[1].toInt(&ok);
+ if (!ok)
+ return QPageRanges();
+
+ if (number1 < 1 || number2 < 1 || number2 < number1)
+ return QPageRanges();
+
+ intervals.append({number1, number2});
+
+ } else {
+ bool ok;
+ const int number = item.toInt(&ok);
+ if (!ok)
+ return QPageRanges();
+
+ if (number < 1)
+ return QPageRanges();
+
+ intervals.append({number, number});
+ }
+ }
+
+ QPageRanges newRanges;
+ newRanges.d.reset(new QPageRangesPrivate);
+ newRanges.d->intervals = intervals;
+ newRanges.d->mergeIntervals();
+ return newRanges;
+}
+
+/*!
+ Returns the string representation of the page ranges.
+*/
+QString QPageRanges::toString() const
+{
+ if (!d)
+ return QString();
+
+ QString result;
+ for (const Range &range : d->intervals) {
+ if (!result.isEmpty())
+ result += u',';
+
+ if (range.from == range.to)
+ result += QString::number(range.from);
+ else
+ result += QStringLiteral("%1-%2").arg(range.from).arg(range.to);
+ }
+
+ return result;
+}
+
+/*!
+ \fn bool QPageRanges::contains(int pageNumber) const
+
+ Returns \c true if the ranges include the page \a pageNumber;
+ otherwise returns \c false.
+*/
+bool QPageRanges::contains(int pageNumber) const
+{
+ if (!d)
+ return false;
+
+ for (const Range &range : d->intervals) {
+ if (range.from <= pageNumber && range.to >= pageNumber)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns \c true if the ranges are empty; otherwise returns \c false.
+*/
+bool QPageRanges::isEmpty() const
+{
+ return !d || d->intervals.isEmpty();
+}
+
+/*!
+ Returns the index of the first page covered by the page ranges,
+ or 0 if the page ranges are empty.
+*/
+int QPageRanges::firstPage() const
+{
+ if (isEmpty())
+ return 0;
+ return d->intervals.constFirst().from;
+}
+
+/*!
+ Returns the index of the last page covered by the page ranges,
+ or 0 if the page ranges are empty.
+*/
+int QPageRanges::lastPage() const
+{
+ if (isEmpty())
+ return 0;
+ return d->intervals.constLast().to;
+}
+
+/*!
+ \internal
+*/
+bool QPageRanges::isEqual(const QPageRanges &other) const noexcept
+{
+ if (d == other.d)
+ return true;
+ if (!d || !other.d)
+ return false;
+ return d->intervals == other.d->intervals;
+}
+
+/*!
+ \internal
+*/
+void QPageRanges::detach()
+{
+ if (d)
+ d.detach();
+ else
+ d.reset(new QPageRangesPrivate);
+}
+
+#if !defined(QT_NO_DATASTREAM)
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QPageRanges &pageRanges)
+ \relates QPageRanges
+
+ Writes \a pageRanges to \a stream as a range string.
+
+ \sa QPageRanges::toString
+*/
+
+QDataStream &operator<<(QDataStream &s, const QPageRanges &pageRanges)
+{
+ s << pageRanges.toString();
+ return s;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QPageRanges &pageRanges)
+ \relates QPageRanges
+
+ Reads a page ranges string from \a stream and stores it in \a pageRanges.
+
+ \sa QPageRanges::fromString
+*/
+
+QDataStream &operator>>(QDataStream &s, QPageRanges &pageRanges)
+{
+ QString rangesString;
+ s >> rangesString;
+ pageRanges = QPageRanges::fromString(rangesString);
+ return s;
+}
+#endif // QT_NO_DATASTREAM
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QPageRanges &pageRanges)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg.noquote();
+ dbg << "QPageRanges(" << pageRanges.toString() << ")";
+
+ return dbg;
+}
+#endif
+
+/*!
+ \struct QPageRanges::Range
+ \inmodule QtGui
+ \brief The QPageRanges::Range struct holds the \c from and \c to endpoints of a range.
+
+ \sa QPageRanges::toRangeList()
+*/
+
+/*!
+ \variable QPageRanges::Range::from
+ \brief the lower endpoint of the range
+*/
+
+/*!
+ \variable QPageRanges::Range::to
+ \brief the upper endpoint of the range
+*/
+
+/*!
+ \fn bool QPageRanges::Range::contains(int pageNumber) const
+
+ Returns \c true if \a pageNumber is within the interval \c{[from, to]};
+ otherwise returns \c false.
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qpageranges.h b/src/gui/painting/qpageranges.h
new file mode 100644
index 0000000000..d0e282fbf2
--- /dev/null
+++ b/src/gui/painting/qpageranges.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPAGERANGES_H
+#define QPAGERANGES_H
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+class QDataStream;
+class QPageRangesPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QPageRangesPrivate, Q_GUI_EXPORT)
+
+class Q_GUI_EXPORT QPageRanges
+{
+public:
+ QPageRanges();
+ ~QPageRanges();
+
+ QPageRanges(const QPageRanges &other) noexcept;
+ QPageRanges &operator=(const QPageRanges &other) noexcept;
+
+ QPageRanges(QPageRanges &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPageRanges)
+ void swap(QPageRanges &other) noexcept
+ { d.swap(other.d); }
+
+ friend bool operator==(const QPageRanges &lhs, const QPageRanges &rhs) noexcept
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QPageRanges &lhs, const QPageRanges &rhs) noexcept
+ { return !lhs.isEqual(rhs); }
+
+ struct Range {
+ int from = -1;
+ int to = -1;
+ bool contains(int pageNumber) const noexcept
+ { return from <= pageNumber && to >= pageNumber; }
+ friend bool operator==(Range lhs, Range rhs) noexcept
+ { return lhs.from == rhs.from && lhs.to == rhs.to; }
+ friend bool operator!=(Range lhs, Range rhs) noexcept
+ { return !(lhs == rhs); }
+ friend bool operator<(Range lhs, Range rhs) noexcept
+ { return lhs.from < rhs.from || (!(rhs.from < lhs.from) && lhs.to < rhs.to); }
+ };
+
+ void addPage(int pageNumber);
+ void addRange(int from, int to);
+ QList<Range> toRangeList() const;
+ void clear();
+
+ QString toString() const;
+ static QPageRanges fromString(const QString &ranges);
+
+ bool contains(int pageNumber) const;
+ bool isEmpty() const;
+ int firstPage() const;
+ int lastPage() const;
+
+ void detach();
+
+private:
+ bool isEqual(const QPageRanges &other) const noexcept;
+
+ QExplicitlySharedDataPointer<QPageRangesPrivate> d;
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPageRanges &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPageRanges &);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QPageRanges &pageRanges);
+#endif
+
+Q_DECLARE_SHARED(QPageRanges)
+Q_DECLARE_TYPEINFO(QPageRanges::Range, Q_RELOCATABLE_TYPE);
+
+QT_END_NAMESPACE
+
+QT_DECL_METATYPE_EXTERN(QPageRanges, Q_GUI_EXPORT)
+
+#endif // QPAGERANGES_H
diff --git a/src/gui/painting/qpageranges_p.h b/src/gui/painting/qpageranges_p.h
new file mode 100644
index 0000000000..37f41a1e11
--- /dev/null
+++ b/src/gui/painting/qpageranges_p.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPAGERANGES_P_H
+#define QPAGERANGES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPageRangesPrivate : public QSharedData
+{
+public:
+ void mergeIntervals();
+
+ QList<QPageRanges::Range> intervals;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPAGERANGES_P_H
diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp
index 324881ec6b..37f66fe63d 100644
--- a/src/gui/painting/qpagesize.cpp
+++ b/src/gui/painting/qpagesize.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpagesize.h"
@@ -48,6 +12,12 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+QT_IMPL_METATYPE_EXTERN(QPageSize)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QPageSize::PageSizeId, QPageSize__PageSizeId)
+QT_IMPL_METATYPE_EXTERN_TAGGED(QPageSize::Unit, QPageSize__Unit)
+
// Define the Windows DMPAPER sizes for use in the look-up table
// See http://msdn.microsoft.com/en-us/library/windows/desktop/dd319099.aspx
@@ -224,16 +194,16 @@ static const int qt_windowsConversion[][2] = {
// Standard sizes data
struct StandardPageSize {
- QPageSize::PageSizeId id;
- int windowsId; // Windows DMPAPER value
- QPageSize::Unit definitionUnits; // Standard definition size, e.g. ISO uses mm, ANSI uses inches
- int widthPoints;
- int heightPoints;
+ QPageSize::PageSizeId id : 8;
+ int windowsId : 16; // Windows DMPAPER value
+ QPageSize::Unit definitionUnits : 8; // Standard definition size, e.g. ISO uses mm, ANSI uses inches
+ int widthPoints : 16;
+ int heightPoints : 16;
qreal widthMillimeters;
qreal heightMillimeters;
qreal widthInches;
qreal heightInches;
- const char *mediaOption; // PPD standard mediaOption ID
+ const char mediaOption[20]; // PPD standard mediaOption ID
};
// Standard page sizes taken from the Postscript PPD Standard v4.3
@@ -242,9 +212,7 @@ struct StandardPageSize {
// NB! This table needs to be in sync with QPageSize::PageSizeId
static const StandardPageSize qt_pageSizes[] = {
- // Existing Qt sizes including ISO, US, ANSI and other standards
- {QPageSize::A4 , DMPAPER_A4 , QPageSize::Millimeter, 595, 842, 210 , 297 , 8.27, 11.69, "A4"},
- {QPageSize::B5 , DMPAPER_NONE , QPageSize::Millimeter, 499, 709, 176 , 250 , 6.9 , 9.8 , "ISOB5"},
+ // Old Qt sizes including ISO, US, ANSI and other standards
{QPageSize::Letter , DMPAPER_LETTER , QPageSize::Inch , 612, 792, 215.9, 279.4, 8.5 , 11 , "Letter"},
{QPageSize::Legal , DMPAPER_LEGAL , QPageSize::Inch , 612, 1008, 215.9, 355.6, 8.5 , 14 , "Legal"},
{QPageSize::Executive , DMPAPER_NONE , QPageSize::Inch , 540, 720, 190.5, 254 , 7.5 , 10 , "Executive.7.5x10in"}, // Qt size differs from Postscript / Windows
@@ -252,21 +220,24 @@ static const StandardPageSize qt_pageSizes[] = {
{QPageSize::A1 , DMPAPER_NONE , QPageSize::Millimeter, 1684, 2384, 594 , 841 , 23.39, 33.11, "A1"},
{QPageSize::A2 , DMPAPER_A2 , QPageSize::Millimeter, 1191, 1684, 420 , 594 , 16.54, 23.39, "A2"},
{QPageSize::A3 , DMPAPER_A3 , QPageSize::Millimeter, 842, 1191, 297 , 420 , 11.69, 16.54, "A3"},
+ {QPageSize::A4 , DMPAPER_A4 , QPageSize::Millimeter, 595, 842, 210 , 297 , 8.27, 11.69, "A4"},
{QPageSize::A5 , DMPAPER_A5 , QPageSize::Millimeter, 420, 595, 148 , 210 , 5.83, 8.27, "A5"},
{QPageSize::A6 , DMPAPER_A6 , QPageSize::Millimeter, 297, 420, 105 , 148 , 4.13, 5.83, "A6"},
{QPageSize::A7 , DMPAPER_NONE , QPageSize::Millimeter, 210, 297, 74 , 105 , 2.91, 4.13, "A7"},
{QPageSize::A8 , DMPAPER_NONE , QPageSize::Millimeter, 148, 210, 52 , 74 , 2.05, 2.91, "A8"},
{QPageSize::A9 , DMPAPER_NONE , QPageSize::Millimeter, 105, 148, 37 , 52 , 1.46, 2.05, "A9"},
+ {QPageSize::A10 , DMPAPER_NONE , QPageSize::Millimeter, 73, 105, 26 , 37 , 1.02, 1.46, "A10"},
{QPageSize::B0 , DMPAPER_NONE , QPageSize::Millimeter, 2835, 4008, 1000 , 1414 , 39.37, 55.67, "ISOB0"},
{QPageSize::B1 , DMPAPER_NONE , QPageSize::Millimeter, 2004, 2835, 707 , 1000 , 27.83, 39.37, "ISOB1"},
- {QPageSize::B10 , DMPAPER_NONE , QPageSize::Millimeter, 88, 125, 31 , 44 , 1.22, 1.73, "ISOB10"},
{QPageSize::B2 , DMPAPER_NONE , QPageSize::Millimeter, 1417, 2004, 500 , 707 , 19.68, 27.83, "ISOB2"},
{QPageSize::B3 , DMPAPER_NONE , QPageSize::Millimeter, 1001, 1417, 353 , 500 , 13.9 , 19.68, "ISOB3"},
{QPageSize::B4 , DMPAPER_ISO_B4 , QPageSize::Millimeter, 709, 1001, 250 , 353 , 9.84, 13.9 , "ISOB4"},
+ {QPageSize::B5 , DMPAPER_NONE , QPageSize::Millimeter, 499, 709, 176 , 250 , 6.9 , 9.8 , "ISOB5"},
{QPageSize::B6 , DMPAPER_NONE , QPageSize::Millimeter, 354, 499, 125 , 176 , 4.92, 6.93, "ISOB6"},
{QPageSize::B7 , DMPAPER_NONE , QPageSize::Millimeter, 249, 354, 88 , 125 , 3.46, 4.92, "ISOB7"},
{QPageSize::B8 , DMPAPER_NONE , QPageSize::Millimeter, 176, 249, 62 , 88 , 2.44, 3.46, "ISOB8"},
{QPageSize::B9 , DMPAPER_NONE , QPageSize::Millimeter, 125, 176, 44 , 62 , 1.73, 2.44, "ISOB9"},
+ {QPageSize::B10 , DMPAPER_NONE , QPageSize::Millimeter, 88, 125, 31 , 44 , 1.22, 1.73, "ISOB10"},
{QPageSize::C5E , DMPAPER_ENV_C5 , QPageSize::Millimeter, 459, 649, 162 , 229 , 6.38, 9.02, "EnvC5"},
{QPageSize::Comm10E , DMPAPER_ENV_10 , QPageSize::Inch , 297, 684, 104.8, 241.3, 4.12, 9.5 , "Env10"},
{QPageSize::DLE , DMPAPER_ENV_DL , QPageSize::Millimeter, 312, 624, 110 , 220 , 4.33, 8.66, "EnvDL"},
@@ -276,7 +247,6 @@ static const StandardPageSize qt_pageSizes[] = {
{QPageSize::Custom , DMPAPER_USER , QPageSize::Millimeter, -1, -1, -1. , -1 , -1 , -1 , "Custom"}, // Special case to keep in sync with QPageSize::PageSizeId
// ISO Standard Sizes
- {QPageSize::A10 , DMPAPER_NONE , QPageSize::Millimeter, 73, 105, 26 , 37 , 1.02, 1.46, "A10"},
{QPageSize::A3Extra , DMPAPER_A3_EXTRA , QPageSize::Millimeter, 913, 1262, 322 , 445 , 12.67, 17.52, "A3Extra"},
{QPageSize::A4Extra , DMPAPER_A4_EXTRA , QPageSize::Millimeter, 667, 914, 235.5, 322.3, 9.27, 12.69, "A4Extra"},
{QPageSize::A4Plus , DMPAPER_A4_PLUS , QPageSize::Millimeter, 595, 936, 210 , 330 , 8.27, 13 , "A4Plus"},
@@ -386,6 +356,7 @@ static const StandardPageSize qt_pageSizes[] = {
static const int pageSizesCount = int(sizeof(qt_pageSizes) / sizeof(qt_pageSizes[0]));
static_assert(pageSizesCount == QPageSize::LastPageSize + 1);
+static_assert(QPageSize::LastPageSize < 256);
// Return key name for PageSize
static QString qt_keyForPageSizeId(QPageSize::PageSizeId id)
@@ -400,12 +371,12 @@ static QPageSize::PageSizeId qt_idForPpdKey(const QString &ppdKey, QSize *match
return QPageSize::Custom;
QStringView key(ppdKey);
// Remove any Rotated or Tranverse modifiers
- if (key.endsWith(QLatin1String("Rotated")))
+ if (key.endsWith("Rotated"_L1))
key.chop(7);
- else if (key.endsWith(QLatin1String(".Transverse")))
+ else if (key.endsWith(".Transverse"_L1))
key.chop(11);
for (int i = 0; i <= int(QPageSize::LastPageSize); ++i) {
- if (QLatin1String(qt_pageSizes[i].mediaOption) == key) {
+ if (QLatin1StringView(qt_pageSizes[i].mediaOption) == key) {
if (match)
*match = QSize(qt_pageSizes[i].widthPoints, qt_pageSizes[i].heightPoints);
return qt_pageSizes[i].id;
@@ -572,7 +543,7 @@ static QSize qt_convertPointsToPixels(const QSize &size, int resolution)
if (!size.isValid() || resolution <= 0)
return QSize();
const qreal multiplier = qt_pixelMultiplier(resolution);
- return QSize(qRound(size.width() / multiplier), qRound(size.height() / multiplier));
+ return QSize(qFloor(size.width() / multiplier), qFloor(size.height() / multiplier));
}
static QSizeF qt_convertPointsToUnits(const QSize &size, QPageSize::Unit units)
@@ -898,7 +869,7 @@ QSizeF QPageSizePrivate::size(QPageSize::Unit units) const
QSize QPageSizePrivate::sizePixels(int resolution) const
{
- return qt_convertPointsToPixels(m_pointSize, resolution);;
+ return qt_convertPointsToPixels(m_pointSize, resolution);
}
@@ -1079,8 +1050,6 @@ QSize QPageSizePrivate::sizePixels(int resolution) const
\value EnvelopePrc10
\value EnvelopeYou4
\value LastPageSize = EnvelopeYou4
- \omitvalue NPageSize
- \omitvalue NPaperSize
Due to historic reasons QPageSize::Executive is not the same as the standard
Postscript and Windows Executive size, use QPageSize::ExecutiveStandard instead.
@@ -1251,20 +1220,15 @@ QPageSize &QPageSize::operator=(const QPageSize &other)
*/
/*!
- \relates QPageSize
+ \fn bool QPageSize::operator==(const QPageSize &lhs, const QPageSize &rhs)
Returns \c true if page size \a lhs is equal to page size \a rhs,
i.e. if the page sizes have the same attributes. Current
attributes are size and name.
*/
-bool operator==(const QPageSize &lhs, const QPageSize &rhs)
-{
- return lhs.d == rhs.d || *lhs.d == *rhs.d;
-}
/*!
- \fn bool operator!=(const QPageSize &lhs, const QPageSize &rhs)
- \relates QPageSize
+ \fn bool QPageSize::operator!=(const QPageSize &lhs, const QPageSize &rhs)
Returns \c true if page size \a lhs is unequal to page size \a
rhs, i.e. if the page size has different attributes. Current
@@ -1272,6 +1236,15 @@ bool operator==(const QPageSize &lhs, const QPageSize &rhs)
*/
/*!
+ \internal
+*/
+bool QPageSize::equals(const QPageSize &other) const
+{
+ return d == other.d || *d == *other.d;
+}
+
+
+/*!
Returns \c true if this page is equivalent to the \a other page, i.e. if the
page has the same size regardless of other attributes like name.
*/
diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h
index 133274760f..b3629bb8d2 100644
--- a/src/gui/painting/qpagesize.h
+++ b/src/gui/painting/qpagesize.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2014 John Layt <jlayt@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAGESIZE_H
#define QPAGESIZE_H
@@ -58,12 +22,8 @@ class Q_GUI_EXPORT QPageSize
{
public:
- // ### Qt6 Re-order and remove duplicates
- // NOTE: Must keep in sync with QPagedPrintEngine and QPrinter
enum PageSizeId {
- // Existing Qt sizes
- A4,
- B5,
+ // Old Qt sizes
Letter,
Legal,
Executive,
@@ -71,21 +31,24 @@ public:
A1,
A2,
A3,
+ A4,
A5,
A6,
A7,
A8,
A9,
+ A10,
B0,
B1,
- B10,
B2,
B3,
B4,
+ B5,
B6,
B7,
B8,
B9,
+ B10,
C5E,
Comm10E,
DLE,
@@ -95,7 +58,6 @@ public:
Custom,
// New values derived from PPD standard
- A10,
A3Extra,
A4Extra,
A4Plus,
@@ -198,10 +160,8 @@ public:
EnvelopePrc10,
EnvelopeYou4,
- // Last item, with commonly used synynoms from QPagedPrintEngine / QPrinter
+ // Last item
LastPageSize = EnvelopeYou4,
- NPageSize = LastPageSize,
- NPaperSize = LastPageSize,
// Convenience overloads for naming consistency
AnsiA = Letter,
@@ -228,7 +188,7 @@ public:
};
QPageSize();
- explicit QPageSize(PageSizeId pageSizeId);
+ Q_IMPLICIT QPageSize(PageSizeId pageSizeId);
explicit QPageSize(const QSize &pointSize,
const QString &name = QString(),
SizeMatchPolicy matchPolicy = FuzzyMatch);
@@ -236,12 +196,12 @@ public:
const QString &name = QString(),
SizeMatchPolicy matchPolicy = FuzzyMatch);
QPageSize(const QPageSize &other);
- QPageSize &operator=(QPageSize &&other) noexcept { swap(other); return *this; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPageSize)
QPageSize &operator=(const QPageSize &other);
~QPageSize();
- void swap(QPageSize &other) noexcept { qSwap(d, other.d); }
+ void swap(QPageSize &other) noexcept { d.swap(other.d); }
friend Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs);
bool isEquivalentTo(const QPageSize &other) const;
@@ -287,6 +247,13 @@ public:
private:
friend class QPageSizePrivate;
friend class QPlatformPrintDevice;
+
+ bool equals(const QPageSize &other) const;
+ friend inline bool operator==(const QPageSize &lhs, const QPageSize &rhs)
+ { return lhs.equals(rhs); }
+ friend inline bool operator!=(const QPageSize &lhs, const QPageSize &rhs)
+ { return !(lhs == rhs); }
+
QPageSize(const QString &key, const QSize &pointSize, const QString &name);
QPageSize(int windowsId, const QSize &pointSize, const QString &name);
QPageSize(QPageSizePrivate &dd);
@@ -295,18 +262,14 @@ private:
Q_DECLARE_SHARED(QPageSize)
-Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs);
-inline bool operator!=(const QPageSize &lhs, const QPageSize &rhs)
-{ return !operator==(lhs, rhs); }
-
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QPageSize &pageSize);
#endif
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QPageSize)
-Q_DECLARE_METATYPE(QPageSize::PageSizeId)
-Q_DECLARE_METATYPE(QPageSize::Unit)
+QT_DECL_METATYPE_EXTERN(QPageSize, Q_GUI_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QPageSize::PageSizeId, QPageSize__PageSizeId, Q_GUI_EXPORT)
+QT_DECL_METATYPE_EXTERN_TAGGED(QPageSize::Unit, QPageSize__Unit, Q_GUI_EXPORT)
#endif // QPAGESIZE_H
diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp
index 4afb89b52e..14e2d7cd8e 100644
--- a/src/gui/painting/qpaintdevice.cpp
+++ b/src/gui/painting/qpaintdevice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpaintdevice.h"
@@ -43,7 +7,6 @@ QT_BEGIN_NAMESPACE
QPaintDevice::QPaintDevice() noexcept
{
- reserved = nullptr;
painters = 0;
}
diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h
index 5f8dad205d..ceccac5e7e 100644
--- a/src/gui/painting/qpaintdevice.h
+++ b/src/gui/painting/qpaintdevice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTDEVICE_H
#define QPAINTDEVICE_H
@@ -49,7 +13,6 @@ QT_BEGIN_NAMESPACE
class QPaintEngine;
-class QPaintDevicePrivate;
class Q_GUI_EXPORT QPaintDevice // device for QPainter
{
@@ -83,8 +46,8 @@ public:
int logicalDpiY() const { return metric(PdmDpiY); }
int physicalDpiX() const { return metric(PdmPhysicalDpiX); }
int physicalDpiY() const { return metric(PdmPhysicalDpiY); }
- int devicePixelRatio() const { return metric(PdmDevicePixelRatio); }
- qreal devicePixelRatioF() const { return metric(PdmDevicePixelRatioScaled) / devicePixelRatioFScale(); }
+ qreal devicePixelRatio() const { return metric(PdmDevicePixelRatioScaled) / devicePixelRatioFScale(); }
+ qreal devicePixelRatioF() const { return devicePixelRatio(); }
int colorCount() const { return metric(PdmNumColors); }
int depth() const { return metric(PdmDepth); }
@@ -100,8 +63,6 @@ protected:
private:
Q_DISABLE_COPY(QPaintDevice)
- QPaintDevicePrivate *reserved;
-
friend class QPainter;
friend class QPainterPrivate;
friend class QFontEngineMac;
diff --git a/src/gui/painting/qpaintdevice.qdoc b/src/gui/painting/qpaintdevice.qdoc
index 3b93faed84..d63fdcb92b 100644
--- a/src/gui/painting/qpaintdevice.qdoc
+++ b/src/gui/painting/qpaintdevice.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QPaintDevice
@@ -123,7 +99,7 @@
The constant scaling factor used is devicePixelRatioFScale(). This enum value
has been introduced in Qt 5.6.
- \sa metric(), devicePixelRatioF()
+ \sa metric(), devicePixelRatio()
*/
/*!
@@ -284,7 +260,7 @@
*/
/*!
- \fn int QPaintDevice::devicePixelRatio() const
+ \fn qreal QPaintDevice::devicePixelRatio() const
Returns the device pixel ratio for device.
diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp
index fc5c125b72..aface3744d 100644
--- a/src/gui/painting/qpaintengine.cpp
+++ b/src/gui/painting/qpaintengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpaintengine.h"
#include "qpaintengine_p.h"
#include "qpainter_p.h"
@@ -44,11 +8,15 @@
#include <qdebug.h>
#include <qmath.h>
#include <qguiapplication.h>
-#include <private/qtextengine_p.h>
#include <qvarlengtharray.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformpixmap.h>
#include <private/qfontengine_p.h>
+#include <private/qguiapplication_p.h>
#include <private/qpaintengineex_p.h>
+#include <private/qtextengine_p.h>
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -182,7 +150,7 @@ QFont QTextItem::font() const
emulated results. Some features cannot be emulated: AlphaBlend and PorterDuff.
\value AlphaBlend The engine can alpha blend primitives.
- \value Antialiasing The engine can use antialising to improve the appearance
+ \value Antialiasing The engine can use antialiasing to improve the appearance
of rendered primitives.
\value BlendModes The engine supports blending modes.
\value BrushStroke The engine supports drawing strokes that
@@ -375,7 +343,6 @@ void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDraw
\value CoreGraphics \macos's Quartz2D (CoreGraphics)
\value QuickDraw \macos's QuickDraw
\value QWindowSystem Qt for Embedded Linux
- \value PostScript (No longer supported)
\value OpenGL
\value Picture QPicture format
\value SVG Scalable Vector Graphics XML format
@@ -447,7 +414,7 @@ void QPaintEngine::drawPoints(const QPointF *points, int pointCount)
p->save();
QTransform transform;
- if (qt_pen_is_cosmetic(p->pen(), p->renderHints())) {
+ if (p->pen().isCosmetic()) {
transform = p->transform();
p->setTransform(QTransform());
}
@@ -514,6 +481,8 @@ void QPaintEngine::drawEllipse(const QRectF &rect)
}
/*!
+ \overload
+
The default implementation of this function calls the floating
point version of this function
*/
@@ -764,7 +733,7 @@ void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
bool((painter()->renderHints() & QPainter::TextAntialiasing)
&& !(painter()->font().styleStrategy() & QFont::NoAntialias)));
for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
- QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixed(), QTransform());
+ QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixedPoint(), QTransform());
painter()->drawImage(positions[i].x.toReal(), positions[i].y.toReal(), glyph);
}
painter()->restore();
@@ -995,6 +964,43 @@ QRect QPaintEngine::systemRect() const
return d_func()->systemRect;
}
+/*!
+ \internal
+
+ Creates a QPixmap optimized for this paint engine and device.
+*/
+QPixmap QPaintEngine::createPixmap(QSize size)
+{
+ if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
+ qWarning("QPaintEngine::createPixmap: QPixmap cannot be created without a QGuiApplication");
+ return QPixmap();
+ }
+
+ std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
+ data->resize(size.width(), size.height());
+ return QPixmap(data.release());
+}
+
+/*!
+ \internal
+
+ Creates a QPixmap optimized for this paint engine and device.
+*/
+QPixmap QPaintEngine::createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags)
+{
+ if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
+ qWarning("QPaintEngine::createPixmapFromImage: QPixmap cannot be created without a QGuiApplication");
+ return QPixmap();
+ }
+
+ std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
+ if (image.isDetached())
+ data->fromImageInPlace(image, flags);
+ else
+ data->fromImage(image, flags);
+ return QPixmap(data.release());
+}
+
QPaintEnginePrivate::~QPaintEnginePrivate()
{
}
diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h
index 73727e463d..f624dda5c7 100644
--- a/src/gui/painting/qpaintengine.h
+++ b/src/gui/painting/qpaintengine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINE_H
#define QPAINTENGINE_H
@@ -195,7 +159,6 @@ public:
Windows,
QuickDraw, CoreGraphics, MacPrinter,
QWindowSystem,
- PostScript, // ### Qt 6: Remove, update documentation
OpenGL,
Picture,
SVG,
@@ -219,13 +182,16 @@ public:
inline void setDirty(DirtyFlags df);
inline void clearDirty(DirtyFlags df);
- bool hasFeature(PaintEngineFeatures feature) const { return gccaps & feature; }
+ bool hasFeature(PaintEngineFeatures feature) const { return bool(gccaps & feature); }
QPainter *painter() const;
void syncState();
inline bool isExtended() const { return extended; }
+ virtual QPixmap createPixmap(QSize size);
+ virtual QPixmap createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags = Qt::AutoColor);
+
protected:
QPaintEngine(QPaintEnginePrivate &data, PaintEngineFeatures devcaps=PaintEngineFeatures());
@@ -318,7 +284,7 @@ inline void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h)
inline bool QPaintEngine::testDirty(DirtyFlags df) {
Q_ASSERT(state);
- return state->dirtyFlags & df;
+ return bool(state->dirtyFlags & df);
}
inline void QPaintEngine::setDirty(DirtyFlags df) {
@@ -329,7 +295,7 @@ inline void QPaintEngine::setDirty(DirtyFlags df) {
inline void QPaintEngine::clearDirty(DirtyFlags df)
{
Q_ASSERT(state);
- state->dirtyFlags &= ~static_cast<uint>(df);
+ state->dirtyFlags &= ~df;
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QTextItem::RenderFlags)
diff --git a/src/gui/painting/qpaintengine_blitter.cpp b/src/gui/painting/qpaintengine_blitter.cpp
index a50d1dfd73..4e6931de09 100644
--- a/src/gui/painting/qpaintengine_blitter.cpp
+++ b/src/gui/painting/qpaintengine_blitter.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qpaintengine_blitter_p.h"
diff --git a/src/gui/painting/qpaintengine_blitter_p.h b/src/gui/painting/qpaintengine_blitter_p.h
index fb5dfe2318..0eb8703b08 100644
--- a/src/gui/painting/qpaintengine_blitter_p.h
+++ b/src/gui/painting/qpaintengine_blitter_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINE_BLITTER_P_H
#define QPAINTENGINE_BLITTER_P_H
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index 40b9474165..210e577950 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINE_P_H
#define QPAINTENGINE_P_H
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5123171fff..f62373d4ef 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qglobal.h>
#include <QtCore/qmutex.h>
@@ -49,7 +13,7 @@
#include <qpainterpath.h>
#include <qdebug.h>
#include <qbitmap.h>
-#include <qmath.h>
+#include "qmath_p.h"
#include <qrandom.h>
// #include <private/qdatabuffer_p.h>
@@ -57,7 +21,6 @@
#include <private/qtextengine_p.h>
#include <private/qfontengine_p.h>
#include <private/qpixmap_raster_p.h>
-// #include <private/qpolygonclipper_p.h>
// #include <private/qrasterizer_p.h>
#include <private/qimage_p.h>
#include <private/qstatictext_p.h>
@@ -135,7 +98,6 @@ public:
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
-#define qreal_to_fixed_26_6(f) (int(f * 64))
#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
@@ -152,8 +114,6 @@ void dumpClip(int width, int height, const QClipData *clip);
// 4 pixels.
#define int_dim(pos, dim) (int(pos+dim) - int(pos))
-static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
-
#ifdef Q_OS_WIN
static inline bool winClearTypeFontsEnabled()
@@ -183,9 +143,9 @@ bool QRasterPaintEngine::clearTypeFontsEnabled()
/********************************************************************************
* Span functions
*/
-static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
-static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
-static void qt_span_clip(int count, const QSpan *spans, void *userData);
+static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans, void *userData);
+static void qt_span_fill_clipped(int count, const QT_FT_Span *spans, void *userData);
+static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData);
struct ClipData
{
@@ -271,35 +231,6 @@ static void qt_debug_path(const QPainterPath &path)
}
#endif
-// QRect::normalized() will change the width/height of the rectangle due to
-// its incusive-integer definition of left/right vs width. This is not
-// something we want to change in QRect as that would potentially introduce
-// regressions all over the place, so we implement a straightforward
-// normalized here. QRectF already does this, so QRectF::normalized() is ok to
-// use.
-static QRect qrect_normalized(const QRect &rect)
-{
- int x, y, w, h;
- if (Q_UNLIKELY(rect.width() < 0)) {
- x = rect.x() + rect.width();
- w = -rect.width();
- } else {
- x = rect.x();
- w = rect.width();
- }
-
- if (Q_UNLIKELY(rect.height() < 0)) {
- y = rect.y() + rect.height();
- h = -rect.height();
- } else {
- y = rect.y();
- h = rect.height();
- }
-
- return QRect(x, y, w, h);
-}
-
-
QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
QPaintEngineExPrivate(),
cachedLines(0)
@@ -309,8 +240,7 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
/*!
\class QRasterPaintEngine
- \preliminary
- \ingroup qws
+ \internal
\inmodule QtGui
\since 4.2
@@ -339,21 +269,12 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
\sa QPaintEngine
*/
-/*!
+/*
\fn QPaintEngine::Type QRasterPaintEngine::type() const
\reimp
*/
/*!
- \typedef QSpan
- \relates QRasterPaintEngine
-
- A struct equivalent to QT_FT_Span, containing a position (x,
- y), the span's length in pixels and its color/coverage (a value
- ranging from 0 to 255).
-*/
-
-/*!
\since 4.5
Creates a raster based paint engine for operating on the given
@@ -484,22 +405,16 @@ bool QRasterPaintEngine::begin(QPaintDevice *device)
QRasterPaintEngineState *s = state();
ensureOutlineMapper();
- d->outlineMapper->m_clip_rect = d->deviceRect;
-
- if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
- d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
- if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
- d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
-
+ d->outlineMapper->setClipRect(d->deviceRect);
d->rasterizer->setClipRect(d->deviceRect);
s->penData.init(d->rasterBuffer.data(), this);
- s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
+ s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
s->stroker = &d->basicStroker;
d->basicStroker.setClipRect(d->deviceRect);
s->brushData.init(d->rasterBuffer.data(), this);
- s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
+ s->brushData.setup(s->brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
@@ -558,31 +473,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
QRasterPaintEngineState *s = state();
// FALCON: get rid of this line, see drawImage call below.
s->matrix = matrix;
- QTransform::TransformationType txop = s->matrix.type();
-
- switch (txop) {
-
- case QTransform::TxNone:
- s->flags.int_xform = true;
- break;
-
- case QTransform::TxTranslate:
- s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
- && qreal(int(s->matrix.dy())) == s->matrix.dy();
- break;
-
- case QTransform::TxScale:
- s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
- && qreal(int(s->matrix.dy())) == s->matrix.dy()
- && qreal(int(s->matrix.m11())) == s->matrix.m11()
- && qreal(int(s->matrix.m22())) == s->matrix.m22();
- break;
-
- default: // shear / perspective...
- s->flags.int_xform = false;
- break;
- }
-
s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
ensureOutlineMapper();
@@ -609,15 +499,15 @@ QRasterPaintEngineState::QRasterPaintEngineState()
txscale = 1.;
+ flag_bits = 0;
flags.fast_pen = true;
flags.non_complex_pen = false;
flags.antialiased = false;
flags.bilinear = false;
- flags.legacy_rounding = false;
flags.fast_text = true;
- flags.int_xform = true;
flags.tx_noshear = true;
flags.fast_images = true;
+ flags.cosmetic_brush = true;
clip = nullptr;
flags.has_clip_ownership = false;
@@ -716,7 +606,8 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
s->strokeFlags = 0;
s->penData.clip = d->clip();
- s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
+ s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity,
+ s->composition_mode, s->flags.cosmetic_brush);
if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
|| pen.brush().transform().type() >= QTransform::TxNone) {
@@ -741,12 +632,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
else
d->basicStroker.setStrokeWidth(penWidth);
- if(pen_style == Qt::SolidLine) {
+ if (pen_style == Qt::SolidLine) {
s->stroker = &d->basicStroker;
} else if (pen_style != Qt::NoPen) {
if (!d->dashStroker)
d->dashStroker.reset(new QDashStroker(&d->basicStroker));
- if (qt_pen_is_cosmetic(pen, s->renderHints)) {
+ if (pen.isCosmetic()) {
d->dashStroker->setClipRect(d->deviceRect);
} else {
// ### I've seen this inverted devrect multiple places now...
@@ -761,7 +652,7 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
}
ensureRasterState(); // needed because of tx_noshear...
- bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints);
+ bool cosmetic = pen.isCosmetic();
s->flags.fast_pen = pen_style > Qt::NoPen
&& s->penData.blend
&& ((cosmetic && penWidth <= 1)
@@ -815,7 +706,7 @@ void QRasterPaintEngine::updateBrush(const QBrush &brush)
QRasterPaintEngineState *s = state();
// must set clip prior to setup, as setup uses it...
s->brushData.clip = d->clip();
- s->brushData.setup(brush, s->intOpacity, s->composition_mode);
+ s->brushData.setup(brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
if (s->fillFlags & DirtyTransform
|| brush.transform().type() >= QTransform::TxNone)
d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
@@ -842,7 +733,8 @@ void QRasterPaintEngine::updateRasterState()
&& s->intOpacity == 256
&& (mode == QPainter::CompositionMode_SourceOver
|| (mode == QPainter::CompositionMode_Source
- && s->penData.solidColor.isOpaque()));
+ && (s->penData.solidColor.spec() != QColor::ExtendedRgb &&
+ s->penData.solidColor.alphaF() >= 1.0f)));
}
s->dirty = 0;
@@ -901,21 +793,25 @@ void QRasterPaintEngine::renderHintsChanged()
bool was_aa = s->flags.antialiased;
bool was_bilinear = s->flags.bilinear;
+ bool was_cosmetic_brush = s->flags.cosmetic_brush;
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
- s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
+ s->flags.cosmetic_brush = !bool(s->renderHints & QPainter::NonCosmeticBrushPatterns);
if (was_aa != s->flags.antialiased)
s->strokeFlags |= DirtyHints;
- if (was_bilinear != s->flags.bilinear) {
+ if (was_bilinear != s->flags.bilinear || was_cosmetic_brush != s->flags.cosmetic_brush) {
s->strokeFlags |= DirtyPen;
s->fillFlags |= DirtyBrush;
}
Q_D(QRasterPaintEngine);
d->recalculateFastImages();
+
+ if (was_aa != s->flags.antialiased)
+ d->updateClipping();
}
/*!
@@ -1003,7 +899,7 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
if (iw <= 0)
return;
- // adapt the y paremeters...
+ // adapt the y parameters...
int cy1 = clip.y();
int cy2 = clip.y() + clip.height();
int y = qRound(pt.y());
@@ -1073,7 +969,7 @@ void QRasterPaintEnginePrivate::blitImage(const QPointF &pt,
if (iw <= 0)
return;
- // adapt the y paremeters...
+ // adapt the y parameters...
int cy1 = clip.y();
int cy2 = clip.y() + clip.height();
int y = qRound(pt.y());
@@ -1251,7 +1147,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
#endif
const qreal *points = path.points();
QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
- if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
+ if (setClipRectInDeviceCoords(qt_mapFillRect(r, s->matrix), op))
return;
}
}
@@ -1310,7 +1206,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
QPaintEngineEx::clip(rect, op);
return;
- } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(QRectF(rect)).toRect(), op)) {
+ } else if (!setClipRectInDeviceCoords(qt_mapFillRect(rect, s->matrix), op)) {
QPaintEngineEx::clip(rect, op);
return;
}
@@ -1320,9 +1216,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
{
Q_D(QRasterPaintEngine);
- // normalize before using the & operator which uses QRect::normalize()
- // internally which will give us the wrong values.
- QRect clipRect = qrect_normalized(r) & d->deviceRect;
+ QRect clipRect = r & d->deviceRect;
QRasterPaintEngineState *s = state();
if (op == Qt::ReplaceClip || s->clip == nullptr) {
@@ -1505,16 +1399,17 @@ static void fillRect_normalized(const QRect &r, QSpanData *data,
if (data->fillRect && (mode == QPainter::CompositionMode_Source
|| (mode == QPainter::CompositionMode_SourceOver
- && data->solidColor.isOpaque())))
+ && (data->solidColor.spec() != QColor::ExtendedRgb &&
+ data->solidColor.alphaF() >= 1.0f))))
{
- data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor);
+ data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor.rgba64());
return;
}
}
ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
- const int nspans = 256;
+ const int nspans = 512;
QT_FT_Span spans[nspans];
Q_ASSERT(data->blend);
@@ -1557,7 +1452,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
int offset_x = int(s->matrix.dx());
int offset_y = int(s->matrix.dy());
while (r < lastRect) {
- QRect rect = qrect_normalized(*r);
+ QRect rect = r->normalized();
QRect rr = rect.translated(offset_x, offset_y);
fillRect_normalized(rr, &s->brushData, d);
++r;
@@ -1576,7 +1471,6 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
stroker.drawPath(path);
@@ -1623,7 +1517,6 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
QRectVectorPath path;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
stroker.drawPath(path);
@@ -1657,23 +1550,23 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(path);
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
- qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints)
+ qreal width = s->lastPen.isCosmetic()
? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
: qpen_widthf(s->lastPen) * s->txscale;
int dashIndex = 0;
qreal dashOffset = s->lastPen.dashOffset();
bool inDash = true;
qreal patternLength = 0;
- const QVector<qreal> pattern = s->lastPen.dashPattern();
+ const QList<qreal> pattern = s->lastPen.dashPattern();
for (int i = 0; i < pattern.size(); ++i)
patternLength += pattern.at(i);
if (patternLength > 0) {
- int n = qFloor(dashOffset / patternLength);
- dashOffset -= n * patternLength;
+ dashOffset = std::fmod(dashOffset, patternLength);
+ if (dashOffset < 0)
+ dashOffset += patternLength;
while (dashOffset >= pattern.at(dashIndex)) {
dashOffset -= pattern.at(dashIndex);
if (++dashIndex >= pattern.size())
@@ -1688,17 +1581,18 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
for (int i = 0; i < lineCount; ++i) {
- if (lines[i].p1() == lines[i].p2()) {
+ const QLineF line = s->matrix.map(lines[i]);
+ if (line.p1() == line.p2()) {
if (s->lastPen.capStyle() != Qt::FlatCap) {
QPointF p = lines[i].p1();
- QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
+ QLineF mappedline = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
QPointF(p.x() + width*0.5, p.y())));
- d->rasterizer->rasterizeLine(line.p1(), line.p2(), width / line.length());
+ d->rasterizer->rasterizeLine(mappedline.p1(), mappedline.p2(),
+ width / mappedline.length());
}
continue;
}
- const QLineF line = s->matrix.map(lines[i]);
if (qpen_style(s->lastPen) == Qt::SolidLine) {
d->rasterizer->rasterizeLine(line.p1(), line.p2(),
width / line.length(),
@@ -1718,14 +1612,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
QRect QRasterPaintEngine::toNormalizedFillRect(const QRectF &rect)
{
- QRasterPaintEngineState *s = state();
-
- qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
-
- int x1 = qRound(rect.x() + delta);
- int y1 = qRound(rect.y() + delta);
- int x2 = qRound(rect.right() + delta);
- int y2 = qRound(rect.bottom() + delta);
+ int x1 = qRound(rect.x());
+ int y1 = qRound(rect.y());
+ int x2 = qRound(rect.right());
+ int y2 = qRound(rect.bottom());
if (x2 < x1)
qSwap(x1, x2);
@@ -1784,7 +1674,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
QRectF cpRect = path.controlPointRect();
const QRectF pathDeviceRect = s->matrix.mapRect(cpRect);
// Skip paths that by conservative estimates are completely outside the paint device.
- if (!pathDeviceRect.intersects(QRectF(d->deviceRect)))
+ if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid())
return;
ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData);
@@ -1861,6 +1751,19 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
fillRect(r, &s->brushData);
}
+static QColor qPremultiplyWithExtraAlpha(const QColor &c, int alpha)
+{
+ if (alpha == 0)
+ return Qt::transparent;
+ if (c.spec() == QColor::ExtendedRgb) {
+ float r, g, b, a;
+ c.getRgbF(&r, &g, &b, &a);
+ a = a * alpha * (1.f / 256.f);
+ return QColor::fromRgbF(r * a, g * a, b * a, a);
+ }
+ return qPremultiply(combineAlpha256(c.rgba64(), alpha));
+}
+
/*!
\reimp
*/
@@ -1872,9 +1775,9 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
- d->solid_color_filler.solidColor = qPremultiply(combineAlpha256(color.rgba64(), s->intOpacity));
+ d->solid_color_filler.solidColor = qPremultiplyWithExtraAlpha(color, s->intOpacity);
- if (d->solid_color_filler.solidColor.isTransparent()
+ if (d->solid_color_filler.solidColor.alphaF() <= 0.0f
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
return;
}
@@ -1888,14 +1791,14 @@ static inline bool isAbove(const QPointF *a, const QPointF *b)
return a->y() < b->y();
}
-static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
+static bool splitPolygon(const QPointF *points, int pointCount, QList<QPointF> *upper, QList<QPointF> *lower)
{
Q_ASSERT(upper);
Q_ASSERT(lower);
Q_ASSERT(pointCount >= 2);
- QVector<const QPointF *> sorted;
+ QList<const QPointF *> sorted;
sorted.reserve(pointCount);
upper->reserve(pointCount * 3 / 4);
@@ -1911,7 +1814,7 @@ static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF>
const QPointF *end = points + pointCount;
const QPointF *last = end - 1;
- QVector<QPointF> *bin[2] = { upper, lower };
+ QList<QPointF> *bin[2] = { upper, lower };
for (const QPointF *p = points; p < end; ++p) {
int side = p->y() < splitY;
@@ -1952,7 +1855,7 @@ void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, Poly
// max amount of points that raster engine can reliably handle
if (pointCount > maxPoints) {
- QVector<QPointF> upper, lower;
+ QList<QPointF> upper, lower;
if (splitPolygon(points, pointCount, &upper, &lower)) {
fillPolygon(upper.constData(), upper.size(), mode);
@@ -2008,7 +1911,6 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
QVectorPath vp((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
QPaintEngineEx::stroke(vp, s->lastPen);
@@ -2073,7 +1975,6 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPath(vp);
} else {
QPaintEngineEx::stroke(vp, s->lastPen);
@@ -2318,9 +2219,6 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
// subtract it here as we don't use it for image drawing
QTransform old = s->matrix;
- if (s->flags.legacy_rounding)
- s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
-
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
QRgb color = img.pixel(sr_l, sr_t);
switch (img.format()) {
@@ -2340,7 +2238,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
break;
}
- if (d->solid_color_filler.solidColor.isTransparent() && s->composition_mode == QPainter::CompositionMode_SourceOver)
+ if (d->solid_color_filler.solidColor.alphaF() <= 0.0f && s->composition_mode == QPainter::CompositionMode_SourceOver)
return;
d->solid_color_filler.clip = d->clip();
@@ -2363,6 +2261,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
|| d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
{
RotationType rotationType = qRotationType(s->matrix);
+ Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats);
const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
@@ -2405,15 +2304,20 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
QRectF targetBounds = s->matrix.mapRect(r);
bool exceedsPrecision = r.width() > 0x7fff
|| r.height() > 0x7fff
+ || targetBounds.left() < -0x7fff
+ || targetBounds.top() < -0x7fff
+ || targetBounds.right() > 0x7fff
+ || targetBounds.bottom() > 0x7fff
|| targetBounds.width() > 0x7fff
|| targetBounds.height() > 0x7fff
|| s->matrix.m11() >= 512
|| s->matrix.m22() >= 512;
-
if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
if (s->matrix.type() > QTransform::TxScale) {
SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
- if (func && (!clip || clip->hasRectClip)) {
+ // The fast transform methods doesn't really work on small targets, see QTBUG-93475
+ // And it can't antialias the edges
+ if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) {
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
s->matrix, s->intOpacity);
@@ -2438,9 +2342,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
}
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
if (func && (!clip || clip->hasRectClip)) {
+ QRectF tr = qt_mapRect_non_normalizing(r, s->matrix);
+ if (!s->flags.antialiased) {
+ tr.setX(qRound(tr.x()));
+ tr.setY(qRound(tr.y()));
+ tr.setWidth(qRound(tr.width()));
+ tr.setHeight(qRound(tr.height()));
+ }
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
img.bits(), img.bytesPerLine(), img.height(),
- qt_mapRect_non_normalizing(r, s->matrix), sr,
+ tr, sr,
!clip ? d->deviceRect : clip->clipRect,
s->intOpacity);
return;
@@ -2477,13 +2388,10 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
- d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
-
- const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF();
const QRectF &rect = r.normalized();
- const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
- const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
+ const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
+ const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
if (s->flags.tx_noshear)
d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
@@ -2492,13 +2400,12 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
return;
}
#endif
- const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
QPainterPath path;
path.addRect(r);
QTransform m = s->matrix;
s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
m.m21(), m.m22(), m.m23(),
- m.m31() - offs, m.m32() - offs, m.m33());
+ m.m31(), m.m32(), m.m33());
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
@@ -2585,7 +2492,6 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
- d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
const QRectF &rect = r.normalized();
const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
@@ -2643,6 +2549,8 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
return;
QRasterBuffer *rb = d->rasterBuffer.data();
+ if (rb->colorSpace.transferFunction() == QColorSpace::TransferFunction::Linear)
+ useGammaCorrection = false;
const QRect rect(rx, ry, w, h);
const QClipData *clip = d->clip();
@@ -2682,20 +2590,20 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
if (unclipped) {
if (depth == 1) {
if (s->penData.bitmapBlit) {
- s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor,
+ s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl);
return;
}
} else if (depth == 8) {
if (s->penData.alphamapBlit) {
- s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor,
+ s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl, nullptr, useGammaCorrection);
return;
}
} else if (depth == 32) {
// (A)RGB Alpha mask where the alpha component is not used.
if (s->penData.alphaRGBBlit) {
- s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor,
+ s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
(const uint *) scanline, w, h, bpl / 4, nullptr, useGammaCorrection);
return;
}
@@ -2724,10 +2632,10 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
ry = ny;
}
if (depth == 8)
- s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor,
+ s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
scanline, w, h, bpl, clip, useGammaCorrection);
else if (depth == 32)
- s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor,
+ s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
(const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
return;
}
@@ -2752,8 +2660,8 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
if (w <= 0 || h <= 0)
return;
- const int NSPANS = 256;
- QSpan spans[NSPANS];
+ const int NSPANS = 512;
+ QT_FT_Span spans[NSPANS];
int current = 0;
const int x1 = x0 + w;
@@ -2865,6 +2773,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
+ bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
+ && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
+
if (fontEngine->hasInternalCaching()) {
QFontEngine::GlyphFormat neededFormat =
painter()->device()->devType() == QInternal::Widget
@@ -2875,7 +2786,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
neededFormat = QFontEngine::Format_Mono;
for (int i = 0; i < numGlyphs; i++) {
- QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
+ QFixedPoint spp = fontEngine->subPixelPositionFor(positions[i]);
+ if (!verticalSubPixelPositions)
+ spp.y = 0;
const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
if (!alphaMap)
@@ -2900,9 +2813,13 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
Q_UNREACHABLE();
};
+ QFixed y = verticalSubPixelPositions
+ ? qFloor(positions[i].y)
+ : qRound(positions[i].y);
+
alphaPenBlt(alphaMap->data, bytesPerLine, depth,
qFloor(positions[i].x) + alphaMap->x,
- qRound(positions[i].y) - alphaMap->y,
+ qFloor(y) - alphaMap->y,
alphaMap->width, alphaMap->height,
fontEngine->expectsGammaCorrectedBlending());
}
@@ -2911,13 +2828,13 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
QImageTextureGlyphCache *cache =
- static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(nullptr, glyphFormat, s->matrix, QColor(s->penData.solidColor)));
+ static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(nullptr, glyphFormat, s->matrix, s->penData.solidColor));
if (!cache) {
- cache = new QImageTextureGlyphCache(glyphFormat, s->matrix, QColor(s->penData.solidColor));
+ cache = new QImageTextureGlyphCache(glyphFormat, s->matrix, s->penData.solidColor);
fontEngine->setGlyphCache(nullptr, cache);
}
- cache->populate(fontEngine, numGlyphs, glyphs, positions);
+ cache->populate(fontEngine, numGlyphs, glyphs, positions, s->renderHints);
cache->fillInPendingGlyphs();
const QImage &image = cache->image();
@@ -2934,15 +2851,20 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
int margin = fontEngine->glyphMargin(glyphFormat);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
+ QFixedPoint subPixelPosition = fontEngine->subPixelPositionFor(positions[i]);
+ if (!verticalSubPixelPositions)
+ subPixelPosition.y = 0;
- QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords[glyph];
if (c.isNull())
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qRound(positions[i].y) - c.baseLineY - margin;
+ int y = (verticalSubPixelPositions
+ ? qFloor(positions[i].y)
+ : qRound(positions[i].y));
+ y -= c.baseLineY + margin;
// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
// c.x, c.y,
@@ -3006,8 +2928,8 @@ bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
Q_Q(const QRasterPaintEngine);
const QRasterPaintEngineState *s = q->state();
const QClipData *cl = clip();
+ QRect r = rect.normalized();
if (!cl) {
- QRect r = qrect_normalized(rect);
// inline contains() for performance (we know the rects are normalized)
const QRect &r1 = deviceRect;
return (r.left() >= r1.left() && r.right() <= r1.right()
@@ -3022,7 +2944,6 @@ bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
if (s->flags.antialiased)
++penWidth;
- QRect r = qrect_normalized(rect);
if (penWidth > 0) {
r.setX(r.x() - penWidth);
r.setY(r.y() - penWidth);
@@ -3044,7 +2965,7 @@ inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
int penWidth) const
{
const QRectF norm = rect.normalized();
- if (norm.left() < INT_MIN || norm.top() < INT_MIN
+ if (norm.left() <= INT_MIN || norm.top() <= INT_MIN
|| norm.right() > INT_MAX || norm.bottom() > INT_MAX
|| norm.width() > INT_MAX || norm.height() > INT_MAX)
return false;
@@ -3078,13 +2999,19 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
}
-static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
- glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
+struct VisibleGlyphRange
+{
+ int begin;
+ int end;
+};
+
+static VisibleGlyphRange visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
+ glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
{
- QFixed clipLeft = QFixed::fromReal(clip.left());
- QFixed clipRight = QFixed::fromReal(clip.right());
- QFixed clipTop = QFixed::fromReal(clip.top());
- QFixed clipBottom = QFixed::fromReal(clip.bottom());
+ QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
+ QFixed clipRight = QFixed::fromReal(clip.right() + 1);
+ QFixed clipTop = QFixed::fromReal(clip.top() - 1);
+ QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
int first = 0;
while (first < numGlyphs) {
@@ -3108,7 +3035,7 @@ static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEn
break;
--last;
}
- return QPair<int, int>(first, last + 1);
+ return {first, last + 1};
}
/*!
@@ -3134,13 +3061,13 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
if (!invertible)
return;
- QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
- textItem->fontEngine(), textItem->glyphs,
- textItem->glyphPositions, textItem->numGlyphs);
+ const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+ textItem->fontEngine(), textItem->glyphs,
+ textItem->glyphPositions, textItem->numGlyphs);
QStaticTextItem copy = *textItem;
- copy.glyphs += range.first;
- copy.glyphPositions += range.first;
- copy.numGlyphs = range.second - range.first;
+ copy.glyphs += range.begin;
+ copy.glyphPositions += range.begin;
+ copy.numGlyphs = range.end - range.begin;
QPaintEngineEx::drawStaticTextItem(&copy);
} else {
QPaintEngineEx::drawStaticTextItem(textItem);
@@ -3189,20 +3116,20 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
ti.flags, glyphs, positions);
- QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
- ti.fontEngine, glyphs.data(), positions.data(),
- glyphs.size());
+ const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+ ti.fontEngine, glyphs.data(), positions.data(),
+ glyphs.size());
- if (range.first >= range.second)
+ if (range.begin >= range.end)
return;
QStaticTextItem staticTextItem;
staticTextItem.color = s->pen.color();
staticTextItem.font = s->font;
staticTextItem.setFontEngine(ti.fontEngine);
- staticTextItem.numGlyphs = range.second - range.first;
- staticTextItem.glyphs = glyphs.data() + range.first;
- staticTextItem.glyphPositions = positions.data() + range.first;
+ staticTextItem.numGlyphs = range.end - range.begin;
+ staticTextItem.glyphs = glyphs.data() + range.begin;
+ staticTextItem.glyphPositions = positions.data() + range.begin;
QPaintEngineEx::drawStaticTextItem(&staticTextItem);
} else {
QPaintEngineEx::drawTextItem(p, ti);
@@ -3227,7 +3154,6 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
}
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
@@ -3247,7 +3173,6 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
}
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
stroker.drawPoints(points, pointCount);
}
@@ -3268,7 +3193,6 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
const QLine &l = lines[i];
stroker.drawLine(l.p1(), l.p2());
@@ -3289,7 +3213,7 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
const QPen &pen = s->lastPen;
const bool squareCap = (pen.capStyle() == Qt::SquareCap);
- const QVector<qreal> pattern = pen.dashPattern();
+ const QList<qreal> pattern = pen.dashPattern();
qreal patternLength = 0;
for (int i = 0; i < pattern.size(); ++i)
@@ -3300,6 +3224,11 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
qreal length = line.length();
Q_ASSERT(length > 0);
+ if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
+ rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
+ return;
+ }
+
while (length > 0) {
const bool rasterize = *inDash;
qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
@@ -3340,7 +3269,6 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
return;
if (s->flags.fast_pen) {
QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
- stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
for (int i=0; i<lineCount; ++i) {
QLineF line = lines[i];
stroker.drawLine(line.p1(), line.p2());
@@ -3462,23 +3390,25 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp
Q_ASSERT(image.depth() == 1);
- const int spanCount = 256;
+ const int spanCount = 512;
QT_FT_Span spans[spanCount];
int n = 0;
// Boundaries
int w = image.width();
int h = image.height();
- int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
- int ymin = qMax(qRound(pos.y()), 0);
- int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
- int xmin = qMax(qRound(pos.x()), 0);
+ int px = qRound(pos.x());
+ int py = qRound(pos.y());
+ int ymax = qMin(py + h, d->rasterBuffer->height());
+ int ymin = qMax(py, 0);
+ int xmax = qMin(px + w, d->rasterBuffer->width());
+ int xmin = qMax(px, 0);
- int x_offset = xmin - qRound(pos.x());
+ int x_offset = xmin - px;
QImage::Format format = image.format();
for (int y = ymin; y < ymax; ++y) {
- const uchar *src = image.scanLine(y - qRound(pos.y()));
+ const uchar *src = image.scanLine(y - py);
if (format == QImage::Format_MonoLSB) {
for (int x = 0; x < xmax - xmin; ++x) {
int src_x = x + x_offset;
@@ -3566,7 +3496,7 @@ QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
\internal
Returns the bounding rect of the currently set clip.
*/
-QRect QRasterPaintEngine::clipBoundingRect() const
+QRectF QRasterPaintEngine::clipBoundingRect() const
{
Q_D(const QRasterPaintEngine);
@@ -3578,7 +3508,7 @@ QRect QRasterPaintEngine::clipBoundingRect() const
if (clip->hasRectClip)
return clip->clipRect;
- return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
+ return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
}
void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
@@ -3587,7 +3517,6 @@ void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
QRasterPaintEngineState *s = q->state();
rasterizer->setAntialiased(s->flags.antialiased);
- rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
QRect clipRect(deviceRect);
ProcessSpans blend;
@@ -3652,7 +3581,6 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
if (!s->flags.antialiased) {
rasterizer->setAntialiased(s->flags.antialiased);
- rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
rasterizer->setClipRect(deviceRect);
rasterizer->initialize(callback, userData);
@@ -3733,6 +3661,18 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
free(rasterPoolOnHeap);
}
+void QRasterPaintEnginePrivate::updateClipping()
+{
+ Q_Q(QRasterPaintEngine);
+ QRasterPaintEngineState *s = q->state();
+
+ if (!s->clipEnabled)
+ return;
+
+ qrasterpaintengine_state_setNoClip(s);
+ replayClipOperations();
+}
+
void QRasterPaintEnginePrivate::recalculateFastImages()
{
Q_Q(QRasterPaintEngine);
@@ -3773,15 +3713,9 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo
QImage::Format dFormat = rasterBuffer->format;
QImage::Format sFormat = image.format();
- // Formats must match or source format must be a subset of destination format
- if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
- if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
- || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)
- || (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64))
- sFormat = dFormat;
- else
- sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
- }
+ // Formats must match or source format must be an opaque version of destination format
+ if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
+ dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
return (dFormat == sFormat);
}
@@ -3791,6 +3725,8 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
+ if (sourceImage.isNull() || dest.isNull())
+ return image; // we must have run out of memory
QRgb fg = qPremultiply(color.rgba());
QRgb bg = 0;
@@ -3800,8 +3736,6 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
for (int y=0; y<height; ++y) {
const uchar *source = sourceImage.constScanLine(y);
QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
- if (!source || !target)
- QT_THROW(std::bad_alloc()); // we must have run out of memory
for (int x=0; x < width; ++x)
target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
}
@@ -3829,9 +3763,10 @@ QImage::Format QRasterBuffer::prepare(QImage *image)
bytes_per_line = image->bytesPerLine();
format = image->format();
+ colorSpace = image->colorSpace();
if (image->depth() == 1 && image->colorTable().size() == 2) {
monoDestinationWithClut = true;
- const QVector<QRgb> colorTable = image->colorTable();
+ const QList<QRgb> colorTable = image->colorTable();
destColor0 = qPremultiply(colorTable[0]);
destColor1 = qPremultiply(colorTable[1]);
}
@@ -3867,23 +3802,23 @@ void QClipData::initialize()
return;
if (!m_clipLines)
- m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
+ m_clipLines = (ClipLine *)calloc(clipSpanHeight, sizeof(ClipLine));
Q_CHECK_PTR(m_clipLines);
QT_TRY {
allocated = clipSpanHeight;
+ count = 0;
QT_TRY {
if (hasRegionClip) {
const auto rects = clipRegion.begin();
const int numRects = clipRegion.rectCount();
const int maxSpans = (ymax - ymin) * numRects;
allocated = qMax(allocated, maxSpans);
- m_spans = (QSpan *)malloc(allocated * sizeof(QSpan));
+ m_spans = (QT_FT_Span *)malloc(allocated * sizeof(QT_FT_Span));
Q_CHECK_PTR(m_spans);
int y = 0;
int firstInBand = 0;
- count = 0;
while (firstInBand < numRects) {
const int currMinY = rects[firstInBand].y();
const int currMaxY = currMinY + rects[firstInBand].height();
@@ -3905,7 +3840,7 @@ void QClipData::initialize()
for (int r = firstInBand; r <= lastInBand; ++r) {
const QRect &currRect = rects[r];
- QSpan *span = m_spans + count;
+ QT_FT_Span *span = m_spans + count;
span->x = currRect.x();
span->len = currRect.width();
span->y = y;
@@ -3929,7 +3864,7 @@ void QClipData::initialize()
return;
}
- m_spans = (QSpan *)malloc(allocated * sizeof(QSpan));
+ m_spans = (QT_FT_Span *)malloc(allocated * sizeof(QT_FT_Span));
Q_CHECK_PTR(m_spans);
if (hasRectClip) {
@@ -3941,9 +3876,8 @@ void QClipData::initialize()
}
const int len = clipRect.width();
- count = 0;
while (y < ymax) {
- QSpan *span = m_spans + count;
+ QT_FT_Span *span = m_spans + count;
span->x = xmin;
span->len = len;
span->y = y;
@@ -4082,16 +4016,16 @@ void QClipData::setClipRegion(const QRegion &region)
\internal
spans must be sorted on y
*/
-static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
- const QSpan *spans, const QSpan *end,
- QSpan **outSpans, int available)
+static const QT_FT_Span *qt_intersect_spans(const QClipData *clip, int *currentClip,
+ const QT_FT_Span *spans, const QT_FT_Span *end,
+ QT_FT_Span **outSpans, int available)
{
const_cast<QClipData *>(clip)->initialize();
- QSpan *out = *outSpans;
+ QT_FT_Span *out = *outSpans;
- const QSpan *clipSpans = clip->m_spans + *currentClip;
- const QSpan *clipEnd = clip->m_spans + clip->count;
+ const QT_FT_Span *clipSpans = clip->m_spans + *currentClip;
+ const QT_FT_Span *clipEnd = clip->m_spans + clip->count;
while (available && spans < end ) {
if (clipSpans >= clipEnd) {
@@ -4145,19 +4079,19 @@ static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
return spans;
}
-static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
+static void qt_span_fill_clipped(int spanCount, const QT_FT_Span *spans, void *userData)
{
// qDebug() << "qt_span_fill_clipped" << spanCount;
QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
Q_ASSERT(fillData->blend && fillData->unclipped_blend);
- const int NSPANS = 256;
- QSpan cspans[NSPANS];
+ const int NSPANS = 512;
+ QT_FT_Span cspans[NSPANS];
int currentClip = 0;
- const QSpan *end = spans + spanCount;
+ const QT_FT_Span *end = spans + spanCount;
while (spans < end) {
- QSpan *clipped = cspans;
+ QT_FT_Span *clipped = cspans;
spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
// qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
// << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
@@ -4175,10 +4109,10 @@ static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userDa
static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans,
const QRect &clip)
{
- const short minx = clip.left();
- const short miny = clip.top();
- const short maxx = clip.right();
- const short maxy = clip.bottom();
+ const int minx = clip.left();
+ const int miny = clip.top();
+ const int maxx = clip.right();
+ const int maxy = clip.bottom();
QT_FT_Span *end = spans + numSpans;
while (spans < end) {
@@ -4200,7 +4134,7 @@ static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans,
s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
s->x = minx;
} else {
- s->len = qMin(s->len, ushort(maxx - s->x + 1));
+ s->len = qMin(s->len, (maxx - s->x + 1));
}
++s;
}
@@ -4209,7 +4143,7 @@ static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans,
}
-static void qt_span_fill_clipRect(int count, const QSpan *spans,
+static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans,
void *userData)
{
QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
@@ -4218,7 +4152,7 @@ static void qt_span_fill_clipRect(int count, const QSpan *spans,
Q_ASSERT(fillData->clip);
Q_ASSERT(!fillData->clip->clipRect.isEmpty());
- QSpan *s = const_cast<QSpan *>(spans);
+ QT_FT_Span *s = const_cast<QT_FT_Span *>(spans);
// hw: check if this const_cast<> is safe!!!
count = qt_intersect_spans(s, count,
fillData->clip->clipRect);
@@ -4226,7 +4160,7 @@ static void qt_span_fill_clipRect(int count, const QSpan *spans,
fillData->unclipped_blend(count, s, fillData);
}
-static void qt_span_clip(int count, const QSpan *spans, void *userData)
+static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData)
{
ClipData *clipData = reinterpret_cast<ClipData *>(userData);
@@ -4243,14 +4177,14 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData)
newClip->initialize();
int currentClip = 0;
- const QSpan *end = spans + count;
+ const QT_FT_Span *end = spans + count;
while (spans < end) {
- QSpan *newspans = newClip->m_spans + newClip->count;
+ QT_FT_Span *newspans = newClip->m_spans + newClip->count;
spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
&newspans, newClip->allocated - newClip->count);
newClip->count = newspans - newClip->m_spans;
if (spans < end) {
- newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
+ newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 * sizeof(QT_FT_Span)));
newClip->allocated *= 2;
}
}
@@ -4268,7 +4202,7 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData)
class QGradientCache
{
public:
- struct CacheInfo : QSpanData::Pinnable
+ struct CacheInfo
{
inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
stops(std::move(s)), opacity(op), interpolationMode(mode) {}
@@ -4279,9 +4213,9 @@ public:
QGradient::InterpolationMode interpolationMode;
};
- typedef QMultiHash<quint64, QSharedPointer<const CacheInfo>> QGradientColorTableHash;
+ using QGradientColorTableHash = QMultiHash<quint64, std::shared_ptr<const CacheInfo>>;
- inline QSharedPointer<const CacheInfo> getBuffer(const QGradient &gradient, int opacity) {
+ std::shared_ptr<const CacheInfo> getBuffer(const QGradient &gradient, int opacity) {
quint64 hash_val = 0;
const QGradientStops stops = gradient.stops();
@@ -4311,16 +4245,16 @@ protected:
inline void generateGradientColorTable(const QGradient& g,
QRgba64 *colorTable,
int size, int opacity) const;
- QSharedPointer<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
+ std::shared_ptr<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
if (cache.size() == maxCacheSize()) {
// may remove more than 1, but OK
cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize())));
}
- auto cache_entry = QSharedPointer<CacheInfo>::create(gradient.stops(), opacity, gradient.interpolationMode());
+ auto cache_entry = std::make_shared<CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode());
generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
for (int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32();
- return cache.insert(hash_val, cache_entry).value();
+ return cache.insert(hash_val, std::move(cache_entry)).value();
}
QGradientColorTableHash cache;
@@ -4330,7 +4264,7 @@ protected:
void QGradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, int opacity) const
{
const QGradientStops stops = gradient.stops();
- int stopCount = stops.count();
+ int stopCount = stops.size();
Q_ASSERT(stopCount > 0);
bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
@@ -4536,7 +4470,8 @@ void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
-void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
+void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode,
+ bool isCosmetic)
{
Qt::BrushStyle brushStyle = qbrush_style(brush);
cachedGradient.reset();
@@ -4544,8 +4479,8 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
case Qt::SolidPattern: {
type = Solid;
QColor c = qbrush_color(brush);
- solidColor = qPremultiply(combineAlpha256(c.rgba64(), alpha));
- if (solidColor.isTransparent() && compositionMode == QPainter::CompositionMode_SourceOver)
+ solidColor = qPremultiplyWithExtraAlpha(c, alpha);
+ if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
type = None;
break;
}
@@ -4558,7 +4493,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
@@ -4582,7 +4517,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
@@ -4610,7 +4545,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
gradient.colorTable32 = cacheInfo->buffer32;
-#if QT_CONFIG(raster_64bit)
+#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
gradient.colorTable64 = cacheInfo->buffer64;
#endif
cachedGradient = std::move(cacheInfo);
@@ -4643,7 +4578,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
if (!tempImage)
tempImage = new QImage();
*tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
- initTexture(tempImage, alpha, QTextureData::Tiled);
+ initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
break;
case Qt::TexturePattern:
type = Texture;
@@ -4909,7 +4844,7 @@ static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
}
}
-/*!
+/*
\fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
\overload
\reimp
@@ -4930,7 +4865,7 @@ void dumpClip(int width, int height, const QClipData *clip)
((QClipData *) clip)->spans(); // Force allocation of the spans structure...
for (int i = 0; i < clip->count; ++i) {
- const QSpan *span = ((QClipData *) clip)->spans() + i;
+ const QT_FT_Span *span = ((QClipData *) clip)->spans() + i;
for (int j = 0; j < span->len; ++j)
clipImg.setPixel(span->x + j, span->y, 0xffffff00);
x0 = qMin(x0, int(span->x));
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 1244ea6709..ab0048af52 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINE_RASTER_P_H
#define QPAINTENGINE_RASTER_P_H
@@ -109,11 +73,10 @@ public:
uint non_complex_pen : 1; // can use rasterizer, rather than stroker
uint antialiased : 1;
uint bilinear : 1;
- uint legacy_rounding : 1;
uint fast_text : 1;
- uint int_xform : 1;
uint tx_noshear : 1;
uint fast_images : 1;
+ uint cosmetic_brush : 1;
};
union {
@@ -206,7 +169,7 @@ public:
ComplexClip
};
ClipType clipType() const;
- QRect clipBoundingRect() const;
+ QRectF clipBoundingRect() const;
#ifdef Q_OS_WIN
void setDC(HDC hdc);
@@ -277,6 +240,7 @@ public:
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, QSpanData *spanData, QRasterBuffer *rasterBuffer);
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *rasterBuffer);
void updateMatrixData(QSpanData *spanData, const QBrush &brush, const QTransform &brushMatrix);
+ void updateClipping();
void systemStateChanged() override;
@@ -351,7 +315,7 @@ public:
int clipSpanHeight;
struct ClipLine {
int count;
- QSpan *spans;
+ QT_FT_Span *spans;
} *m_clipLines;
void initialize();
@@ -362,7 +326,7 @@ public:
return m_clipLines;
}
- inline QSpan *spans() {
+ inline QT_FT_Span *spans() {
if (!m_spans)
initialize();
return m_spans;
@@ -370,7 +334,7 @@ public:
int allocated;
int count;
- QSpan *m_spans;
+ QT_FT_Span *m_spans;
int xmin, xmax, ymin, ymax;
QRect clipRect;
@@ -381,7 +345,7 @@ public:
uint hasRegionClip : 1;
void appendSpan(int x, int length, int y, int coverage);
- void appendSpans(const QSpan *s, int num);
+ void appendSpans(const QT_FT_Span *s, int num);
// ### Should optimize and actually kill the QSpans if the rect is
// ### a subset of The current region. Thus the "fast" clipspan
@@ -397,7 +361,7 @@ inline void QClipData::appendSpan(int x, int length, int y, int coverage)
if (count == allocated) {
allocated *= 2;
- m_spans = (QSpan *)realloc(m_spans, allocated*sizeof(QSpan));
+ m_spans = (QT_FT_Span *)realloc(m_spans, allocated*sizeof(QT_FT_Span));
}
m_spans[count].x = x;
m_spans[count].len = length;
@@ -406,7 +370,7 @@ inline void QClipData::appendSpan(int x, int length, int y, int coverage)
++count;
}
-inline void QClipData::appendSpans(const QSpan *s, int num)
+inline void QClipData::appendSpans(const QT_FT_Span *s, int num)
{
Q_ASSERT(m_spans);
@@ -414,9 +378,9 @@ inline void QClipData::appendSpans(const QSpan *s, int num)
do {
allocated *= 2;
} while (count + num > allocated);
- m_spans = (QSpan *)realloc(m_spans, allocated*sizeof(QSpan));
+ m_spans = (QT_FT_Span *)realloc(m_spans, allocated*sizeof(QT_FT_Span));
}
- memcpy(m_spans+count, s, num*sizeof(QSpan));
+ memcpy(m_spans+count, s, num*sizeof(QT_FT_Span));
count += num;
}
@@ -451,6 +415,7 @@ public:
QPainter::CompositionMode compositionMode;
QImage::Format format;
+ QColorSpace colorSpace;
QImage colorizeBitmap(const QImage &image, const QColor &color);
private:
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 5d8f89eadd..9468876c23 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpaintengineex_p.h"
#include "qpainter_p.h"
@@ -183,7 +147,7 @@ void QPaintEngineExPrivate::replayClipOperations()
if (!p || !p->d_ptr)
return;
- const QVector<QPainterClipInfo> &clipInfo = p->d_ptr->state->clipInfo;
+ const QList<QPainterClipInfo> &clipInfo = p->d_ptr->state->clipInfo;
QTransform transform = q->state()->matrix;
@@ -385,10 +349,10 @@ 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;
+ qDebug() << "QPaintEngineEx::stroke()" << inPen;
#endif
Q_D(QPaintEngineEx);
@@ -403,6 +367,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
+ qreal pw = pen.widthF() ? pen.widthF() : 1;
+ QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
+ qreal extent = qMax(extentRect.width(), extentRect.height());
+ qreal patternLength = 0;
+ const 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));
+ patternLength *= pw;
+ if (qFuzzyIsNull(patternLength)) {
+ pen.setStyle(Qt::NoPen);
+ } else if (extent / patternLength > QDashStroker::repetitionLimit()) {
+ // approximate stream of tiny dashes with semi-transparent solid line
+ pen.setStyle(Qt::SolidLine);
+ QColor color(pen.color());
+ color.setAlpha(color.alpha() / 2);
+ pen.setColor(color);
+ }
+ }
+
if (!qpen_fast_equals(pen, d->strokerPen)) {
d->strokerPen = pen;
d->stroker.setJoinStyle(pen.joinStyle());
@@ -430,14 +426,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
return;
}
- if (pen.style() > Qt::SolidLine) {
- if (qt_pen_is_cosmetic(pen, state()->renderHints)){
- d->activeStroker->setClipRect(d->exDeviceRect);
- } else {
- QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
- d->activeStroker->setClipRect(clipRect);
- }
- }
+ if (!clipRect.isNull())
+ d->activeStroker->setClipRect(clipRect);
if (d->activeStroker == &d->stroker)
d->stroker.setForceOpen(path.hasExplicitOpen());
@@ -461,7 +451,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
flags |= QVectorPath::CurvedShapeMask;
// ### Perspective Xforms are currently not supported...
- if (!qt_pen_is_cosmetic(pen, state()->renderHints)) {
+ if (!pen.isCosmetic()) {
// We include cosmetic pens in this case to avoid having to
// change the current transform. Normal transformed,
// non-cosmetic pens will be transformed as part of fill
@@ -912,6 +902,7 @@ void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
+ Q_ASSERT(pointCount >= 2);
QVectorPath path((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
if (mode == PolylineMode)
@@ -922,6 +913,7 @@ void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonD
void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{
+ Q_ASSERT(pointCount >= 2);
int count = pointCount<<1;
QVarLengthArray<qreal> pts(count);
@@ -939,20 +931,20 @@ void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDr
void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm)
{
- drawPixmap(QRectF(pos, pm.size() / pm.devicePixelRatio()), pm, pm.rect());
+ drawPixmap(QRectF(pos, pm.deviceIndependentSize()), pm, pm.rect());
}
void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image)
{
- drawImage(QRectF(pos, image.size() / image.devicePixelRatio()), image, image.rect());
+ drawImage(QRectF(pos, image.deviceIndependentSize()), image, image.rect());
}
void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
{
QBrush brush(state()->pen.color(), pixmap);
QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
- if (!qFuzzyCompare(pixmap.devicePixelRatioF(), 1.0))
- xform.scale(1.0/pixmap.devicePixelRatioF(), 1.0/pixmap.devicePixelRatioF());
+ if (!qFuzzyCompare(pixmap.devicePixelRatio(), qreal(1.0)))
+ xform.scale(1.0/pixmap.devicePixelRatio(), 1.0/pixmap.devicePixelRatio());
brush.setTransform(xform);
qreal pts[] = { r.x(), r.y(),
diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h
index b2f8b64029..d2a5a9ceab 100644
--- a/src/gui/painting/qpaintengineex_p.h
+++ b/src/gui/painting/qpaintengineex_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTENGINEEX_P_H
#define QPAINTENGINEEX_P_H
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 9272ddb9ef..f4b9741eed 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1,43 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// QtCore
+#include <memory>
#include <qdebug.h>
#include <qmath.h>
#include <qmutex.h>
@@ -74,9 +39,15 @@
#include <private/qhexstring_p.h>
#include <private/qguiapplication_p.h>
#include <private/qrawfont_p.h>
+#include <private/qfont_p.h>
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+// We changed the type from QScopedPointer to unique_ptr, make sure it's binary compatible:
+static_assert(sizeof(QScopedPointer<QPainterPrivate>) == sizeof(std::unique_ptr<QPainterPrivate>));
+
#define QGradient_StretchToDevice 0x10000000
#define QPaintEngine_OpaqueBackground 0x40000000
@@ -180,6 +151,23 @@ static bool qt_painter_thread_test(int devType, int engineType, const char *what
}
#endif
+static bool needsEmulation(const QBrush &brush)
+{
+ bool res = false;
+
+ const QGradient *bg = brush.gradient();
+ if (bg) {
+ res = (bg->coordinateMode() > QGradient::LogicalMode);
+ } else if (brush.style() == Qt::TexturePattern) {
+ if (qHasPixmapTexture(brush))
+ res = !qFuzzyCompare(brush.texture().devicePixelRatio(), qreal(1.0));
+ else
+ res = !qFuzzyCompare(brush.textureImage().devicePixelRatio(), qreal(1.0));
+ }
+
+ return res;
+}
+
void QPainterPrivate::checkEmulation()
{
Q_ASSERT(extended);
@@ -187,43 +175,34 @@ void QPainterPrivate::checkEmulation()
if (state->bgMode == Qt::OpaqueMode)
doEmulation = true;
- const QGradient *bg = state->brush.gradient();
- if (bg && bg->coordinateMode() > QGradient::LogicalMode)
+ if (needsEmulation(state->brush))
doEmulation = true;
- const QGradient *pg = qpen_brush(state->pen).gradient();
- if (pg && pg->coordinateMode() > QGradient::LogicalMode)
+ if (needsEmulation(qpen_brush(state->pen)))
doEmulation = true;
- if (state->brush.style() == Qt::TexturePattern) {
- if (qHasPixmapTexture(state->brush))
- doEmulation |= !qFuzzyCompare(state->brush.texture().devicePixelRatioF(), 1.0);
- else
- doEmulation |= !qFuzzyCompare(state->brush.textureImage().devicePixelRatioF(), 1.0);
- }
-
if (doEmulation && extended->flags() & QPaintEngineEx::DoNotEmulate)
return;
if (doEmulation) {
- if (extended != emulationEngine) {
+ if (extended != emulationEngine.get()) {
if (!emulationEngine)
- emulationEngine = new QEmulationPaintEngine(extended);
- extended = emulationEngine;
- extended->setState(state);
+ emulationEngine = std::make_unique<QEmulationPaintEngine>(extended);
+ extended = emulationEngine.get();
+ extended->setState(state.get());
}
- } else if (emulationEngine == extended) {
+ } else if (emulationEngine.get() == extended) {
extended = emulationEngine->real_engine;
}
}
-
-QPainterPrivate::~QPainterPrivate()
+QPainterPrivate::QPainterPrivate(QPainter *painter)
+ : q_ptr(painter), txinv(0), inDestructor(false)
{
- delete emulationEngine;
- qDeleteAll(states);
}
+QPainterPrivate::~QPainterPrivate()
+ = default;
QTransform QPainterPrivate::viewTransform() const
{
@@ -242,7 +221,7 @@ qreal QPainterPrivate::effectiveDevicePixelRatio() const
if (device->devType() == QInternal::Printer)
return qreal(1);
- return qMax(qreal(1), device->devicePixelRatioF());
+ return device->devicePixelRatio();
}
QTransform QPainterPrivate::hidpiScaleTransform() const
@@ -267,22 +246,10 @@ bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
// Save the current state of the shared painter and assign
// the current d_ptr to the shared painter's d_ptr.
sp->save();
- if (!sp->d_ptr->d_ptrs) {
- // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
- // redirections within the same paintEvent(), which should be enough
- // in 99% of all cases). E.g: A renders B which renders C which renders D.
- sp->d_ptr->d_ptrs_size = 4;
- sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *));
- Q_CHECK_PTR(sp->d_ptr->d_ptrs);
- } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) {
- // However, to support corner cases we grow the array dynamically if needed.
- sp->d_ptr->d_ptrs_size <<= 1;
- const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *);
- sp->d_ptr->d_ptrs = q_check_ptr((QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize));
- }
- sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr.data();
- q->d_ptr.take();
- q->d_ptr.reset(sp->d_ptr.data());
+ ++sp->d_ptr->refcount;
+ sp->d_ptr->d_ptrs.push_back(q->d_ptr.get());
+ Q_UNUSED(q->d_ptr.release());
+ q->d_ptr.reset(sp->d_ptr.get());
Q_ASSERT(q->d_ptr->state);
@@ -325,7 +292,9 @@ void QPainterPrivate::detachPainterPrivate(QPainter *q)
Q_ASSERT(refcount > 1);
Q_ASSERT(q);
- QPainterPrivate *original = d_ptrs[--refcount - 1];
+ --refcount;
+ QPainterPrivate *original = d_ptrs.back();
+ d_ptrs.pop_back();
if (inDestructor) {
inDestructor = false;
if (original)
@@ -334,14 +303,12 @@ void QPainterPrivate::detachPainterPrivate(QPainter *q)
original = new QPainterPrivate(q);
}
- d_ptrs[refcount - 1] = nullptr;
q->restore();
- q->d_ptr.take();
+ Q_UNUSED(q->d_ptr.release());
q->d_ptr.reset(original);
if (emulationEngine) {
extended = emulationEngine->real_engine;
- delete emulationEngine;
emulationEngine = nullptr;
}
}
@@ -414,7 +381,7 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio
if (q->hasClipping()) {
bool hasPerspectiveTransform = false;
- for (const QPainterClipInfo &info : qAsConst(state->clipInfo)) {
+ for (const QPainterClipInfo &info : std::as_const(state->clipInfo)) {
if (info.matrix.type() == QTransform::TxProject) {
hasPerspectiveTransform = true;
break;
@@ -1158,24 +1125,22 @@ void QPainterPrivate::updateState(QPainterState *newState)
The QPainter class also provides a means of controlling the
rendering quality through its RenderHint enum and the support for
floating point precision: All the functions for drawing primitives
- has a floating point version. These are often used in combination
+ have floating point versions.
+
+ \snippet code/src_gui_painting_qpainter.cpp floatBased
+
+ These are often used in combination
with the \l {RenderHint}{QPainter::Antialiasing} render hint.
+ \snippet code/src_gui_painting_qpainter.cpp renderHint
+
\table 100%
\row
+ \li Comparing concentric circles with int and float, and with or without
+ anti-aliased rendering. Using the floating point precision versions
+ produces evenly spaced rings. Anti-aliased rendering results in
+ smooth circles.
\li \inlineimage qpainter-concentriccircles.png
- \li
- \b {Concentric Circles Example}
-
- The \l {painting/concentriccircles}{Concentric Circles} example
- shows the improved rendering quality that can be obtained using
- floating point precision and anti-aliasing when drawing custom
- widgets.
-
- The application's main window displays several widgets which are
- drawn using the various combinations of precision and
- anti-aliasing.
-
\endtable
The RenderHint enum specifies flags to QPainter that may or may
@@ -1235,7 +1200,7 @@ void QPainterPrivate::updateState(QPainterState *newState)
\li \inlineimage qpainter-affinetransformations.png
\endtable
- All the tranformation operations operate on the transformation
+ All the transformation operations operate on the transformation
worldTransform(). A matrix transforms a point in the plane to another
point. For more information about the transformation matrix, see
the \l {Coordinate System} and QTransform documentation.
@@ -1429,10 +1394,15 @@ void QPainterPrivate::updateState(QPainterState *newState)
a smooth pixmap transformation algorithm (such as bilinear) rather
than nearest neighbor.
- \value Qt4CompatiblePainting Compatibility hint telling the engine to use the
- same X11 based fill rules as in Qt 4, where aliased rendering is offset
- by slightly less than half a pixel. Also will treat default constructed pens
- as cosmetic. Potentially useful when porting a Qt 4 application to Qt 5.
+ \value VerticalSubpixelPositioning Allow text to be positioned at fractions
+ of pixels vertically as well as horizontally, if this is supported by the
+ font engine. This is currently supported by Freetype on all platforms when
+ the hinting preference is QFont::PreferNoHinting, and also on macOS. For
+ most use cases this will not improve visual quality, but may increase memory
+ consumption and some reduction in text rendering performance. Therefore, enabling
+ this is not recommended unless the use case requires it. One such use case could
+ be aligning glyphs with other visual primitives.
+ This value was added in Qt 6.1.
\value LosslessImageRendering Use a lossless image rendering, whenever possible.
Currently, this hint is only used when QPainter is employed to output a PDF
@@ -1441,8 +1411,14 @@ void QPainterPrivate::updateState(QPainterState *newState)
JPEG compression.
This value was added in Qt 5.13.
+ \value NonCosmeticBrushPatterns When painting with a brush with one of the predefined pattern
+ styles, transform the pattern too, along with the object being painted. The default is to treat
+ the pattern as cosmetic, so that the pattern pixels will map directly to device pixels,
+ independently of any active transformations.
+ This value was added in Qt 6.4.
+
\sa renderHints(), setRenderHint(), {QPainter#Rendering
- Quality}{Rendering Quality}, {Concentric Circles Example}
+ Quality}{Rendering Quality}
*/
@@ -1511,8 +1487,6 @@ QPainter::~QPainter()
Q_ASSERT(d_ptr->inDestructor);
d_ptr->inDestructor = false;
Q_ASSERT(d_ptr->refcount == 1);
- if (d_ptr->d_ptrs)
- free(d_ptr->d_ptrs);
}
}
@@ -1541,7 +1515,7 @@ QPaintDevice *QPainter::device() const
bool QPainter::isActive() const
{
Q_D(const QPainter);
- return d->engine;
+ return d->engine != nullptr;
}
void QPainterPrivate::initFrom(const QPaintDevice *device)
@@ -1583,15 +1557,19 @@ void QPainter::save()
return;
}
+ std::unique_ptr<QPainterState> prev;
if (d->extended) {
- d->state = d->extended->createState(d->states.back());
- d->extended->setState(d->state);
+ // separate the creation of a new state from the update of d->state, since some
+ // engines access d->state directly (not via createState()'s argument)
+ std::unique_ptr<QPainterState> next(d->extended->createState(d->state.get()));
+ prev = std::exchange(d->state, std::move(next));
+ d->extended->setState(d->state.get());
} else {
d->updateState(d->state);
- d->state = new QPainterState(d->states.back());
- d->engine->state = d->state;
+ prev = std::exchange(d->state, std::make_unique<QPainterState>(d->state.get()));
+ d->engine->state = d->state.get();
}
- d->states.push_back(d->state);
+ d->savedStates.push(std::move(prev));
}
/*!
@@ -1608,7 +1586,7 @@ void QPainter::restore()
printf("QPainter::restore()\n");
#endif
Q_D(QPainter);
- if (d->states.size()<=1) {
+ if (d->savedStates.empty()) {
qWarning("QPainter::restore: Unbalanced save/restore");
return;
} else if (!d->engine) {
@@ -1616,15 +1594,13 @@ void QPainter::restore()
return;
}
- QPainterState *tmp = d->state;
- d->states.pop_back();
- d->state = d->states.back();
+ const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
+ d->savedStates.pop();
d->txinv = false;
if (d->extended) {
d->checkEmulation();
- d->extended->setState(d->state);
- delete tmp;
+ d->extended->setState(d->state.get());
return;
}
@@ -1638,9 +1614,8 @@ void QPainter::restore()
tmp->clipPath = QPainterPath();
d->engine->updateState(*tmp);
// replay the list of clip states,
- for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
+ for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
tmp->matrix = info.matrix;
- tmp->matrix *= d->state->redirectionMatrix;
tmp->clipOperation = info.operation;
if (info.clipType == QPainterClipInfo::RectClip) {
tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
@@ -1662,8 +1637,7 @@ void QPainter::restore()
tmp->changeFlags |= QPaintEngine::DirtyTransform;
}
- d->updateState(d->state);
- delete tmp;
+ d->updateState(d->state.get());
}
@@ -1696,8 +1670,7 @@ void QPainter::restore()
static inline void qt_cleanup_painter_state(QPainterPrivate *d)
{
- qDeleteAll(d->states);
- d->states.clear();
+ d->savedStates.clear();
d->state = nullptr;
d->engine = nullptr;
d->device = nullptr;
@@ -1740,7 +1713,7 @@ bool QPainter::begin(QPaintDevice *pd)
else if (pd->devType() == QInternal::Image)
static_cast<QImage *>(pd)->detach();
- d->engine = pd->paintEngine();
+ d->engine.reset(pd->paintEngine());
if (!d->engine) {
qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
@@ -1749,24 +1722,23 @@ bool QPainter::begin(QPaintDevice *pd)
d->device = pd;
- d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : nullptr;
+ d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine.get()) : nullptr;
if (d->emulationEngine)
d->emulationEngine->real_engine = d->extended;
// Setup new state...
Q_ASSERT(!d->state);
- d->state = d->extended ? d->extended->createState(nullptr) : new QPainterState;
+ d->state.reset(d->extended ? d->extended->createState(nullptr) : new QPainterState);
d->state->painter = this;
- d->states.push_back(d->state);
d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
d->state->brushOrigin = QPointF();
// Slip a painter state into the engine before we do any other operations
if (d->extended)
- d->extended->setState(d->state);
+ d->extended->setState(d->state.get());
else
- d->engine->state = d->state;
+ d->engine->state = d->state.get();
switch (pd->devType()) {
case QInternal::Pixmap:
@@ -1793,9 +1765,12 @@ bool QPainter::begin(QPaintDevice *pd)
qWarning("QPainter::begin: Cannot paint on a null image");
qt_cleanup_painter_state(d);
return false;
- } else if (img->format() == QImage::Format_Indexed8) {
- // Painting on indexed8 images is not supported.
- qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format");
+ } else if (img->format() == QImage::Format_Indexed8 ||
+ img->format() == QImage::Format_CMYK8888) {
+ // Painting on these formats is not supported.
+ qWarning() << "QPainter::begin: Cannot paint on an image with the"
+ << img->format()
+ << "format";
qt_cleanup_painter_state(d);
return false;
}
@@ -1850,7 +1825,7 @@ bool QPainter::begin(QPaintDevice *pd)
Q_ASSERT(d->engine->isActive());
- if (!d->state->redirectionMatrix.isIdentity() || d->effectiveDevicePixelRatio() > 1)
+ if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
d->updateMatrix();
Q_ASSERT(d->engine->isActive());
@@ -1904,22 +1879,13 @@ bool QPainter::end()
}
}
- if (d->states.size() > 1) {
- qWarning("QPainter::end: Painter ended with %d saved states", int(d->states.size()));
- }
-
- if (d->engine->autoDestruct()) {
- delete d->engine;
- }
-
- if (d->emulationEngine) {
- delete d->emulationEngine;
- d->emulationEngine = nullptr;
+ if (d->savedStates.size() > 0) {
+ qWarning("QPainter::end: Painter ended with %d saved states", int(d->savedStates.size()));
}
- if (d->extended) {
- d->extended = nullptr;
- }
+ d->engine.reset();
+ d->emulationEngine = nullptr;
+ d->extended = nullptr;
qt_cleanup_painter_state(d);
@@ -1936,7 +1902,7 @@ bool QPainter::end()
QPaintEngine *QPainter::paintEngine() const
{
Q_D(const QPainter);
- return d->engine;
+ return d->engine.get();
}
/*!
@@ -2512,7 +2478,7 @@ QRegion QPainter::clipRegion() const
const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
// ### Falcon: Use QPainterPath
- for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
+ for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
switch (info.clipType) {
case QPainterClipInfo::RegionClip: {
@@ -2679,7 +2645,7 @@ QRectF QPainter::clipBoundingRect() const
// fast.
QRectF bounds;
bool first = true;
- for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
+ for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
QRectF r;
if (info.clipType == QPainterClipInfo::RectClip)
@@ -3058,7 +3024,8 @@ void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
return;
}
- if ((!d->state->clipEnabled && op != Qt::NoClip))
+ bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
+ if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
op = Qt::ReplaceClip;
if (d->extended) {
@@ -3071,7 +3038,7 @@ void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
return;
}
- if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
+ if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
op = Qt::ReplaceClip;
d->state->clipPath = path;
@@ -3102,12 +3069,9 @@ void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
if (path.isEmpty())
return;
- if (d->extended) {
- const QGradient *g = qpen_brush(pen).gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->stroke(qtVectorPathForPath(path), pen);
- return;
- }
+ if (d->extended && !needsEmulation(pen.brush())) {
+ d->extended->stroke(qtVectorPathForPath(path), pen);
+ return;
}
QBrush oldBrush = d->state->brush;
@@ -3145,12 +3109,9 @@ void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
if (path.isEmpty())
return;
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fill(qtVectorPathForPath(path), brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fill(qtVectorPathForPath(path), brush);
+ return;
}
QBrush oldBrush = d->state->brush;
@@ -3412,14 +3373,14 @@ void QPainter::drawRects(const QRect *rects, int rectCount)
}
/*!
- \fn void QPainter::drawRects(const QVector<QRectF> &rectangles)
+ \fn void QPainter::drawRects(const QList<QRectF> &rectangles)
\overload
Draws the given \a rectangles using the current pen and brush.
*/
/*!
- \fn void QPainter::drawRects(const QVector<QRect> &rectangles)
+ \fn void QPainter::drawRects(const QList<QRect> &rectangles)
\overload
@@ -3578,7 +3539,7 @@ void QPainter::drawPoints(const QPoint *points, int pointCount)
\overload
- Draws the points in the vector \a points.
+ Draws the points in the vector \a points.
*/
/*!
@@ -3586,7 +3547,7 @@ void QPainter::drawPoints(const QPoint *points, int pointCount)
\overload
- Draws the points in the vector \a points.
+ Draws the points in the vector \a points.
*/
/*!
@@ -3881,7 +3842,7 @@ void QPainter::setFont(const QFont &font)
#ifdef QT_DEBUG_DRAW
if (qt_show_painter_debug_output)
- printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.family().toLatin1().constData(), font.pointSize());
+ printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.families().first().toLatin1().constData(), font.pointSize());
#endif
if (!d->engine) {
@@ -3941,8 +3902,10 @@ void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawRoundedRect: Painter not active");
return;
+ }
if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
drawRect(rect);
@@ -4003,8 +3966,10 @@ void QPainter::drawEllipse(const QRectF &r)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawEllipse: Painter not active");
return;
+ }
QRectF rect(r.normalized());
@@ -4044,8 +4009,10 @@ void QPainter::drawEllipse(const QRect &r)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawEllipse: Painter not active");
return;
+ }
QRect rect(r.normalized());
@@ -4131,8 +4098,10 @@ void QPainter::drawArc(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawArc: Painter not active");
return;
+ }
QRectF rect = r.normalized();
@@ -4193,8 +4162,10 @@ void QPainter::drawPie(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawPie: Painter not active");
return;
+ }
if (a > (360*16)) {
a = a % (360*16);
@@ -4262,8 +4233,10 @@ void QPainter::drawChord(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawChord: Painter not active");
return;
+ }
QRectF rect = r.normalized();
@@ -4421,7 +4394,7 @@ void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
/*!
- \fn void QPainter::drawLines(const QVector<QPointF> &pointPairs)
+ \fn void QPainter::drawLines(const QList<QPointF> &pointPairs)
\overload
Draws a line for each pair of points in the vector \a pointPairs
@@ -4430,7 +4403,7 @@ void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
*/
/*!
- \fn void QPainter::drawLines(const QVector<QPoint> &pointPairs)
+ \fn void QPainter::drawLines(const QList<QPoint> &pointPairs)
\overload
Draws a line for each pair of points in the vector \a pointPairs
@@ -4438,7 +4411,7 @@ void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
*/
/*!
- \fn void QPainter::drawLines(const QVector<QLineF> &lines)
+ \fn void QPainter::drawLines(const QList<QLineF> &lines)
\overload
Draws the set of lines defined by the list \a lines using the
@@ -4446,7 +4419,7 @@ void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
*/
/*!
- \fn void QPainter::drawLines(const QVector<QLine> &lines)
+ \fn void QPainter::drawLines(const QList<QLine> &lines)
\overload
Draws the set of lines defined by the list \a lines using the
@@ -5488,9 +5461,13 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
QStaticTextPrivate *staticText_d =
const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
- if (font() != staticText_d->font) {
+ QFontPrivate *fp = QFontPrivate::get(font());
+ QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
+ if (font() != staticText_d->font || fp == nullptr || stfp == nullptr || fp->dpi != stfp->dpi) {
staticText_d->font = font();
staticText_d->needsRelayout = true;
+ } else if (stfp->engineData == nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
+ staticText_d->needsRelayout = true;
}
QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
@@ -5628,7 +5605,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif
}
engine.itemize();
QScriptLine line;
- line.length = str.length();
+ line.length = str.size();
engine.shapeLine(line);
int nItems = engine.layoutData->items.size();
@@ -5683,7 +5660,7 @@ void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br
Q_D(QPainter);
- if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
+ if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
return;
if (!d->extended)
@@ -5770,7 +5747,7 @@ void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *
Q_D(QPainter);
- if (!d->engine || str.length() == 0 || pen().style() == Qt::NoPen)
+ if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
return;
if (!d->extended)
@@ -5889,7 +5866,7 @@ void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption
Q_D(QPainter);
- if (!d->engine || text.length() == 0 || pen().style() == Qt::NoPen)
+ if (!d->engine || text.size() == 0 || pen().style() == Qt::NoPen)
return;
if (!d->extended)
@@ -5929,7 +5906,7 @@ void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption
It ignores the font set on the painter as the text item has one of its own.
The underline and strikeout parameters of the text items font are
- ignored aswell. You'll need to pass in the correct flags to get
+ ignored as well. You'll need to pass in the correct flags to get
underlining and strikeout.
*/
@@ -5937,7 +5914,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
{
const qreal radiusBase = qMax(qreal(1), maxRadius);
- QString key = QLatin1String("WaveUnderline-")
+ QString key = "WaveUnderline-"_L1
% pen.color().name()
% HexString<qreal>(radiusBase)
% HexString<qreal>(pen.widthF());
@@ -6004,12 +5981,6 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
- bool wasCompatiblePainting = painter->renderHints()
- & QPainter::Qt4CompatiblePainting;
-
- if (wasCompatiblePainting)
- painter->setRenderHint(QPainter::Qt4CompatiblePainting, false);
-
const qreal underlineOffset = fe->underlinePosition().toReal();
if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
@@ -6062,6 +6033,9 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
if (flags & QTextItem::StrikeOut) {
QLineF strikeOutLine = line;
strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
+ QColor uc = charFormat.underlineColor();
+ if (uc.isValid())
+ pen.setColor(uc);
painter->setPen(pen);
if (textEngine)
textEngine->addStrikeOut(painter, strikeOutLine);
@@ -6072,6 +6046,9 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
if (flags & QTextItem::Overline) {
QLineF overline = line;
overline.translate(0., - fe->ascent().toReal());
+ QColor uc = charFormat.underlineColor();
+ if (uc.isValid())
+ pen.setColor(uc);
painter->setPen(pen);
if (textEngine)
textEngine->addOverline(painter, overline);
@@ -6081,9 +6058,6 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
painter->setPen(oldPen);
painter->setBrush(oldBrush);
-
- if (wasCompatiblePainting)
- painter->setRenderHint(QPainter::Qt4CompatiblePainting);
}
static void qt_draw_decoration_for_glyphs(QPainter *painter,
@@ -6383,7 +6357,7 @@ QRectF QPainter::boundingRect(const QRectF &r, const QString &text, const QTextO
{
Q_D(QPainter);
- if (!d->engine || text.length() == 0)
+ if (!d->engine || text.size() == 0)
return QRectF(r.x(),r.y(), 0,0);
QRectF br;
@@ -6531,7 +6505,9 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo
painted on a widget or pixmap can also be stored in a picture.
This function does exactly the same as QPicture::play() when
- called with \a point = QPoint(0, 0).
+ called with \a point = QPointF(0, 0).
+
+ \note The state of the painter is preserved by this function.
\table 100%
\row
@@ -6546,8 +6522,10 @@ void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawPicture: Painter not active");
return;
+ }
if (!d->extended)
d->updateState(d->state);
@@ -6658,15 +6636,14 @@ void QPainter::fillRect(const QRectF &r, const QBrush &brush)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fillRect(r, brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fillRect(r, brush);
+ return;
}
QPen oldPen = pen();
@@ -6696,15 +6673,14 @@ void QPainter::fillRect(const QRect &r, const QBrush &brush)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
- if (d->extended) {
- const QGradient *g = brush.gradient();
- if (!g || g->coordinateMode() == QGradient::LogicalMode) {
- d->extended->fillRect(r, brush);
- return;
- }
+ if (d->extended && !needsEmulation(brush)) {
+ d->extended->fillRect(r, brush);
+ return;
}
QPen oldPen = pen();
@@ -6737,8 +6713,10 @@ void QPainter::fillRect(const QRect &r, const QColor &color)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
if (d->extended) {
d->extended->fillRect(r, color);
@@ -7177,19 +7155,19 @@ start_lengthVariant:
// compatible behaviour to the old implementation. Replace
// tabs by spaces
int old_offset = offset;
- for (; offset < text.length(); offset++) {
+ for (; offset < text.size(); offset++) {
QChar chr = text.at(offset);
- if (chr == QLatin1Char('\r') || (singleline && chr == QLatin1Char('\n'))) {
- text[offset] = QLatin1Char(' ');
- } else if (chr == QLatin1Char('\n')) {
+ if (chr == u'\r' || (singleline && chr == u'\n')) {
+ text[offset] = u' ';
+ } else if (chr == u'\n') {
text[offset] = QChar::LineSeparator;
- } else if (chr == QLatin1Char('&')) {
+ } else if (chr == u'&') {
++maxUnderlines;
- } else if (chr == QLatin1Char('\t')) {
+ } else if (chr == u'\t') {
if (!expandtabs) {
- text[offset] = QLatin1Char(' ');
+ text[offset] = u' ';
} else if (!tabarraylen && !tabstops) {
- tabstops = qRound(fm.horizontalAdvance(QLatin1Char('x'))*8);
+ tabstops = qRound(fm.horizontalAdvance(u'x')*8);
}
} else if (chr == u'\x9c') {
// string with multiple length variants
@@ -7198,7 +7176,7 @@ start_lengthVariant:
}
}
- QVector<QTextLayout::FormatRange> underlineFormats;
+ QList<QTextLayout::FormatRange> underlineFormats;
int length = offset - old_offset;
if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
QChar *cout = text.data() + old_offset;
@@ -7206,13 +7184,13 @@ start_lengthVariant:
QChar *cin = cout;
int l = length;
while (l) {
- if (*cin == QLatin1Char('&')) {
+ if (*cin == u'&') {
++cin;
--length;
--l;
if (!l)
break;
- if (*cin != QLatin1Char('&') && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
+ if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
QTextLayout::FormatRange range;
range.start = cout - cout0;
range.length = 1;
@@ -7220,9 +7198,9 @@ start_lengthVariant:
underlineFormats.append(range);
}
#ifdef Q_OS_MAC
- } else if (hidemnmemonic && *cin == QLatin1Char('(') && l >= 4 &&
- cin[1] == QLatin1Char('&') && cin[2] != QLatin1Char('&') &&
- cin[3] == QLatin1Char(')')) {
+ } else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
+ cin[1] == u'&' && cin[2] != u'&' &&
+ cin[3] == u')') {
int n = 0;
while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
++n;
@@ -7283,7 +7261,7 @@ start_lengthVariant:
qreal lineWidth = 0x01000000;
if (wordwrap || (tf & Qt::TextJustificationForced))
lineWidth = qMax<qreal>(0, r.width());
- if(!wordwrap)
+ if (!wordwrap)
tf |= Qt::TextIncludeTrailingSpaces;
textLayout.beginLayout();
@@ -8187,3 +8165,5 @@ void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivat
}
QT_END_NAMESPACE
+
+#include "moc_qpainter.cpp"
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 498e443108..7bcacb4bca 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTER_H
#define QPAINTER_H
@@ -48,6 +12,7 @@
#include <QtGui/qpixmap.h>
#include <QtGui/qimage.h>
#include <QtGui/qtextoption.h>
+#include <memory>
#ifndef QT_INCLUDE_COMPAT
#include <QtGui/qpolygon.h>
@@ -87,10 +52,11 @@ public:
Antialiasing = 0x01,
TextAntialiasing = 0x02,
SmoothPixmapTransform = 0x04,
- Qt4CompatiblePainting = 0x20,
+ VerticalSubpixelPositioning = 0x08,
LosslessImageRendering = 0x40,
+ NonCosmeticBrushPatterns = 0x80
};
- Q_FLAG(RenderHint)
+ Q_ENUM(RenderHint)
Q_DECLARE_FLAGS(RenderHints, RenderHint)
Q_FLAG(RenderHints)
@@ -438,7 +404,7 @@ public:
void setRenderHint(RenderHint hint, bool on = true);
void setRenderHints(RenderHints hints, bool on = true);
RenderHints renderHints() const;
- inline bool testRenderHint(RenderHint hint) const { return renderHints() & hint; }
+ inline bool testRenderHint(RenderHint hint) const { return bool(renderHints() & hint); }
QPaintEngine *paintEngine() const;
@@ -448,7 +414,7 @@ public:
private:
Q_DISABLE_COPY(QPainter)
- QScopedPointer<QPainterPrivate> d_ptr;
+ std::unique_ptr<QPainterPrivate> d_ptr;
friend class QWidget;
friend class QFontEngine;
@@ -502,52 +468,52 @@ inline void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
inline void QPainter::drawLines(const QList<QLineF> &lines)
{
- drawLines(lines.constData(), lines.size());
+ drawLines(lines.constData(), int(lines.size()));
}
inline void QPainter::drawLines(const QList<QLine> &lines)
{
- drawLines(lines.constData(), lines.size());
+ drawLines(lines.constData(), int(lines.size()));
}
inline void QPainter::drawLines(const QList<QPointF> &pointPairs)
{
- drawLines(pointPairs.constData(), pointPairs.size() / 2);
+ drawLines(pointPairs.constData(), int(pointPairs.size() / 2));
}
inline void QPainter::drawLines(const QList<QPoint> &pointPairs)
{
- drawLines(pointPairs.constData(), pointPairs.size() / 2);
+ drawLines(pointPairs.constData(), int(pointPairs.size() / 2));
}
inline void QPainter::drawPolyline(const QPolygonF &polyline)
{
- drawPolyline(polyline.constData(), polyline.size());
+ drawPolyline(polyline.constData(), int(polyline.size()));
}
inline void QPainter::drawPolyline(const QPolygon &polyline)
{
- drawPolyline(polyline.constData(), polyline.size());
+ drawPolyline(polyline.constData(), int(polyline.size()));
}
inline void QPainter::drawPolygon(const QPolygonF &polygon, Qt::FillRule fillRule)
{
- drawPolygon(polygon.constData(), polygon.size(), fillRule);
+ drawPolygon(polygon.constData(), int(polygon.size()), fillRule);
}
inline void QPainter::drawPolygon(const QPolygon &polygon, Qt::FillRule fillRule)
{
- drawPolygon(polygon.constData(), polygon.size(), fillRule);
+ drawPolygon(polygon.constData(), int(polygon.size()), fillRule);
}
inline void QPainter::drawConvexPolygon(const QPolygonF &poly)
{
- drawConvexPolygon(poly.constData(), poly.size());
+ drawConvexPolygon(poly.constData(), int(poly.size()));
}
inline void QPainter::drawConvexPolygon(const QPolygon &poly)
{
- drawConvexPolygon(poly.constData(), poly.size());
+ drawConvexPolygon(poly.constData(), int(poly.size()));
}
inline void QPainter::drawRect(const QRectF &rect)
@@ -568,12 +534,12 @@ inline void QPainter::drawRect(const QRect &r)
inline void QPainter::drawRects(const QList<QRectF> &rects)
{
- drawRects(rects.constData(), rects.size());
+ drawRects(rects.constData(), int(rects.size()));
}
inline void QPainter::drawRects(const QList<QRect> &rects)
{
- drawRects(rects.constData(), rects.size());
+ drawRects(rects.constData(), int(rects.size()));
}
inline void QPainter::drawPoint(const QPointF &p)
@@ -594,12 +560,12 @@ inline void QPainter::drawPoint(const QPoint &p)
inline void QPainter::drawPoints(const QPolygonF &points)
{
- drawPoints(points.constData(), points.size());
+ drawPoints(points.constData(), int(points.size()));
}
inline void QPainter::drawPoints(const QPolygon &points)
{
- drawPoints(points.constData(), points.size());
+ drawPoints(points.constData(), int(points.size()));
}
inline void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius,
diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h
index fe029c66a5..0ddd78fb2a 100644
--- a/src/gui/painting/qpainter_p.h
+++ b/src/gui/painting/qpainter_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTER_P_H
#define QPAINTER_P_H
@@ -66,6 +30,7 @@
#include <private/qpen_p.h>
#include <memory>
+#include <stack>
QT_BEGIN_NAMESPACE
@@ -140,7 +105,7 @@ public:
};
-Q_DECLARE_TYPEINFO(QPainterClipInfo, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QPainterClipInfo, Q_RELOCATABLE_TYPE);
class Q_GUI_EXPORT QPainterState : public QPaintEngineState
{
@@ -193,28 +158,29 @@ class QPainterPrivate
{
Q_DECLARE_PUBLIC(QPainter)
public:
- QPainterPrivate(QPainter *painter)
- : q_ptr(painter), d_ptrs(nullptr), state(nullptr), dummyState(nullptr), txinv(0), inDestructor(false), d_ptrs_size(0),
- refcount(1), device(nullptr), original_device(nullptr), helper_device(nullptr), engine(nullptr), emulationEngine(nullptr),
- extended(nullptr)
- {
- }
-
+ explicit QPainterPrivate(QPainter *painter);
~QPainterPrivate();
QPainter *q_ptr;
- QPainterPrivate **d_ptrs;
-
- QPainterState *state;
- QVarLengthArray<QPainterState *, 8> states;
+ // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
+ // redirections within the same paintEvent(), which should be enough
+ // in 99% of all cases). E.g: A renders B which renders C which renders D.
+ static constexpr qsizetype NDPtrs = 4;
+ QVarLengthArray<QPainterPrivate*, NDPtrs> d_ptrs;
+
+ std::unique_ptr<QPainterState> state;
+ template <typename T, std::size_t N = 8>
+ struct SmallStack : std::stack<T, QVarLengthArray<T, N>> {
+ void clear() { this->c.clear(); }
+ };
+ SmallStack<std::unique_ptr<QPainterState>> savedStates;
mutable std::unique_ptr<QPainterDummyState> dummyState;
QTransform invMatrix;
uint txinv:1;
uint inDestructor : 1;
- uint d_ptrs_size;
- uint refcount;
+ uint refcount = 1;
enum DrawOperation { StrokeDraw = 0x1,
FillDraw = 0x2,
@@ -230,6 +196,7 @@ public:
void updateEmulationSpecifier(QPainterState *s);
void updateStateImpl(QPainterState *state);
void updateState(QPainterState *state);
+ void updateState(std::unique_ptr<QPainterState> &state) { updateState(state.get()); }
void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw);
void drawStretchedGradient(const QPainterPath &path, DrawOperation operation);
@@ -249,7 +216,7 @@ public:
static QPainterPrivate *get(QPainter *painter)
{
- return painter->d_ptr.data();
+ return painter->d_ptr.get();
}
QTransform viewTransform() const;
@@ -259,12 +226,21 @@ public:
void detachPainterPrivate(QPainter *q);
void initFrom(const QPaintDevice *device);
- QPaintDevice *device;
- QPaintDevice *original_device;
- QPaintDevice *helper_device;
- QPaintEngine *engine;
- QEmulationPaintEngine *emulationEngine;
- QPaintEngineEx *extended;
+ QPaintDevice *device = nullptr;
+ QPaintDevice *original_device = nullptr;
+ QPaintDevice *helper_device = nullptr;
+
+ struct QPaintEngineDestructor {
+ void operator()(QPaintEngine *pe) const noexcept
+ {
+ if (pe && pe->autoDestruct())
+ delete pe;
+ }
+ };
+ std::unique_ptr<QPaintEngine, QPaintEngineDestructor> engine;
+
+ std::unique_ptr<QEmulationPaintEngine> emulationEngine;
+ QPaintEngineEx *extended = nullptr;
QBrush colorBrush; // for fill with solid color
};
@@ -272,10 +248,6 @@ Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, Q
QString qt_generate_brush_key(const QBrush &brush);
-inline bool qt_pen_is_cosmetic(const QPen &pen, QPainter::RenderHints hints)
-{
- return pen.isCosmetic() || (const_cast<QPen &>(pen).data_ptr()->defaultWidth && (hints & QPainter::Qt4CompatiblePainting));
-}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index de0b3f3998..8d23d167b0 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpainterpath.h"
#include "qpainterpath_p.h"
@@ -88,17 +52,6 @@ static bool hasValidCoords(QRectF r)
return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
}
-struct QPainterPathPrivateDeleter
-{
- static inline void cleanup(QPainterPathPrivate *d)
- {
- // note - we must downcast to QPainterPathData since QPainterPathPrivate
- // has a non-virtual destructor!
- if (d && !d->ref.deref())
- delete static_cast<QPainterPathData *>(d);
- }
-};
-
// This value is used to determine the length of control point vectors
// when approximating arc segments as curves. The factor is multiplied
// with the radius of the circle.
@@ -556,12 +509,7 @@ QPainterPath::QPainterPath() noexcept
\sa operator=()
*/
-QPainterPath::QPainterPath(const QPainterPath &other)
- : d_ptr(other.d_ptr.data())
-{
- if (d_ptr)
- d_ptr->ref.ref();
-}
+QPainterPath::QPainterPath(const QPainterPath &other) = default;
/*!
Creates a QPainterPath object with the given \a startPoint as its
@@ -569,34 +517,22 @@ QPainterPath::QPainterPath(const QPainterPath &other)
*/
QPainterPath::QPainterPath(const QPointF &startPoint)
- : d_ptr(new QPainterPathData)
+ : d_ptr(new QPainterPathPrivate(startPoint))
{
- Element e = { startPoint.x(), startPoint.y(), MoveToElement };
- d_func()->elements << e;
}
void QPainterPath::detach()
{
- if (d_ptr->ref.loadRelaxed() != 1)
- detach_helper();
+ d_ptr.detach();
setDirty(true);
}
/*!
\internal
*/
-void QPainterPath::detach_helper()
-{
- QPainterPathPrivate *data = new QPainterPathData(*d_func());
- d_ptr.reset(data);
-}
-
-/*!
- \internal
-*/
void QPainterPath::ensureData_helper()
{
- QPainterPathPrivate *data = new QPainterPathData;
+ QPainterPathPrivate *data = new QPainterPathPrivate;
data->elements.reserve(16);
QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
data->elements << e;
@@ -613,12 +549,8 @@ void QPainterPath::ensureData_helper()
*/
QPainterPath &QPainterPath::operator=(const QPainterPath &other)
{
- if (other.d_func() != d_func()) {
- QPainterPathPrivate *data = other.d_func();
- if (data)
- data->ref.ref();
- d_ptr.reset(data);
- }
+ QPainterPath copy(other);
+ swap(copy);
return *this;
}
@@ -668,7 +600,7 @@ void QPainterPath::clear()
Attempts to allocate memory for at least \a size elements.
- \sa clear(), capacity(), QVector::reserve()
+ \sa clear(), capacity(), QList::reserve()
\since 5.13
*/
void QPainterPath::reserve(int size)
@@ -753,7 +685,7 @@ void QPainterPath::moveTo(const QPointF &p)
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
d->require_moveTo = false;
@@ -803,7 +735,7 @@ void QPainterPath::lineTo(const QPointF &p)
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
d->maybeMoveTo();
if (p == QPointF(d->elements.constLast()))
@@ -862,7 +794,7 @@ void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
@@ -1201,6 +1133,9 @@ void QPainterPath::addEllipse(const QRectF &boundingRect)
that the left end of the text's baseline lies at the specified \a
point.
+ Some fonts may yield overlapping subpaths and will require the
+ \c Qt::WindingFill fill rule for correct rendering.
+
\table 100%
\row
\li \inlineimage qpainterpath-addtext.png
@@ -1209,7 +1144,7 @@ void QPainterPath::addEllipse(const QRectF &boundingRect)
\endtable
\sa QPainter::drawText(), {QPainterPath#Composing a
- QPainterPath}{Composing a QPainterPath}
+ QPainterPath}{Composing a QPainterPath}, setFillRule()
*/
void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
{
@@ -1221,6 +1156,11 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
QTextLayout layout(text, f);
layout.setCacheEnabled(true);
+
+ QTextOption opt = layout.textOption();
+ opt.setUseDesignMetrics(true);
+ layout.setTextOption(opt);
+
QTextEngine *eng = layout.engine();
layout.beginLayout();
QTextLine line = layout.createLine();
@@ -1247,7 +1187,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
QGlyphLayout glyphs = eng->shapedGlyphs(&si);
- QFontEngine *fe = f.d->engineForScript(si.analysis.script);
+ QFontEngine *fe = eng->fontEngine(si);
Q_ASSERT(fe);
fe->addOutlineToPath(x, y, glyphs, this,
si.analysis.bidiLevel % 2
@@ -1288,7 +1228,7 @@ void QPainterPath::addPath(const QPainterPath &other)
ensureData();
detach();
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
+ QPainterPathPrivate *d = d_func();
// Remove last moveto so we don't get multiple moveto's
if (d->elements.constLast().type == MoveToElement)
d->elements.remove(d->elements.size()-1);
@@ -1319,7 +1259,7 @@ void QPainterPath::connectPath(const QPainterPath &other)
ensureData();
detach();
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
+ QPainterPathPrivate *d = d_func();
// Remove last moveto so we don't get multiple moveto's
if (d->elements.constLast().type == MoveToElement)
d->elements.remove(d->elements.size()-1);
@@ -1366,7 +1306,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;
}
/*!
@@ -1509,7 +1449,7 @@ QRectF QPainterPath::boundingRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyBounds)
computeBoundingRect();
@@ -1530,7 +1470,7 @@ QRectF QPainterPath::controlPointRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyControlBounds)
computeControlPointRect();
@@ -1549,7 +1489,7 @@ QRectF QPainterPath::controlPointRect() const
bool QPainterPath::isEmpty() const
{
- return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
+ return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.constFirst().type == MoveToElement);
}
/*!
@@ -1692,7 +1632,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
if (count == 0)
return polys;
- QVector<QRectF> bounds;
+ QList<QRectF> bounds;
bounds.reserve(count);
for (int i=0; i<count; ++i)
bounds += subpaths.at(i).boundingRect();
@@ -1703,7 +1643,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
qDebug() << " bounds" << i << bounds.at(i);
#endif
- QVector< QVector<int> > isects;
+ QList< QList<int> > isects;
isects.resize(count);
// find all intersections
@@ -1731,12 +1671,12 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
// flatten the sets of intersections
for (int i=0; i<count; ++i) {
- const QVector<int> &current_isects = isects.at(i);
+ const QList<int> &current_isects = isects.at(i);
for (int j=0; j<current_isects.size(); ++j) {
int isect_j = current_isects.at(j);
if (isect_j == i)
continue;
- const QVector<int> &isects_j = isects.at(isect_j);
+ const QList<int> &isects_j = isects.at(isect_j);
for (int k = 0, size = isects_j.size(); k < size; ++k) {
int isect_k = isects_j.at(k);
if (isect_k != i && !isects.at(i).contains(isect_k)) {
@@ -1760,7 +1700,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
// Join the intersected subpaths as rewinded polygons
for (int i=0; i<count; ++i) {
- const QVector<int> &subpath_list = isects.at(i);
+ const QList<int> &subpath_list = isects.at(i);
if (!subpath_list.isEmpty()) {
QPolygonF buildUp;
for (int j=0; j<subpath_list.size(); ++j) {
@@ -1857,7 +1797,7 @@ bool QPainterPath::contains(const QPointF &pt) const
if (isEmpty() || !controlPointRect().contains(pt))
return false;
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
int winding_number = 0;
@@ -2151,7 +2091,7 @@ bool QPainterPath::intersects(const QRectF &rect) const
Q_D(QPainterPath);
- // Check if the rectangle surounds any subpath...
+ // Check if the rectangle surrounds any subpath...
for (int i=0; i<d->elements.size(); ++i) {
const Element &e = d->elements.at(i);
if (e.type == QPainterPath::MoveToElement && rect.contains(e))
@@ -2316,8 +2256,8 @@ static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSiz
bool QPainterPath::operator==(const QPainterPath &path) const
{
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
- QPainterPathData *other_d = path.d_func();
+ QPainterPathPrivate *d = d_func();
+ QPainterPathPrivate *other_d = path.d_func();
if (other_d == d) {
return true;
} else if (!d || !other_d) {
@@ -2502,14 +2442,14 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
int size;
s >> size;
- if (size == 0)
+ if (size == 0) {
+ p = {};
return s;
+ }
p.ensureData(); // in case if p.d_func() == 0
- if (p.d_func()->elements.size() == 1) {
- Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
- p.d_func()->elements.clear();
- }
+ p.detach();
+ p.d_func()->elements.clear();
for (int i=0; i<size; ++i) {
int type;
double x, y;
@@ -2532,9 +2472,7 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
s >> fillRule;
Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
p.d_func()->fillRule = Qt::FillRule(fillRule);
- p.d_func()->dirtyBounds = true;
- p.d_func()->dirtyControlBounds = true;
- if (errorDetected)
+ if (errorDetected || p.d_func()->elements.isEmpty())
p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
return s;
}
@@ -2592,7 +2530,7 @@ void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
\endlist
The setDashPattern() function accepts both a Qt::PenStyle object
- and a vector representation of the pattern as argument.
+ and a list representation of the pattern as argument.
In addition you can specify a curve's threshold, controlling the
granularity with which a curve is drawn, using the
@@ -2811,16 +2749,16 @@ void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
dashPattern. This function makes it possible to specify custom
dash patterns.
- Each element in the vector contains the lengths of the dashes and spaces
+ Each element in the list contains the lengths of the dashes and spaces
in the stroke, beginning with the first dash in the first element, the
first space in the second element, and alternating between dashes and
spaces for each following pair of elements.
- The vector can contain an odd number of elements, in which case the last
+ The list can contain an odd number of elements, in which case the last
element will be extended by the length of the first element when the
pattern repeats.
*/
-void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
+void QPainterPathStroker::setDashPattern(const QList<qreal> &dashPattern)
{
d_func()->dashPattern.clear();
for (int i=0; i<dashPattern.size(); ++i)
@@ -2830,7 +2768,7 @@ void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
/*!
Returns the dash pattern for the generated outlines.
*/
-QVector<qreal> QPainterPathStroker::dashPattern() const
+QList<qreal> QPainterPathStroker::dashPattern() const
{
return d_func()->dashPattern;
}
@@ -3297,7 +3235,7 @@ QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
*/
QPainterPath QPainterPath::simplified() const
{
- if(isEmpty())
+ if (isEmpty())
return *this;
QPathClipper clipper(*this, QPainterPath());
return clipper.clip(QPathClipper::Simplify);
@@ -3356,7 +3294,7 @@ void QPainterPath::setDirty(bool dirty)
void QPainterPath::computeBoundingRect() const
{
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
d->dirtyBounds = false;
if (!d_ptr) {
d->bounds = QRect();
@@ -3403,7 +3341,7 @@ void QPainterPath::computeBoundingRect() const
void QPainterPath::computeControlPointRect() const
{
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
d->dirtyControlBounds = false;
if (!d_ptr) {
d->controlBounds = QRect();
diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h
index c6bb68e35a..4caf1aa5c0 100644
--- a/src/gui/painting/qpainterpath.h
+++ b/src/gui/painting/qpainterpath.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTERPATH_H
#define QPAINTERPATH_H
@@ -46,7 +10,7 @@
#include <QtCore/qline.h>
#include <QtCore/qlist.h>
#include <QtCore/qrect.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@@ -54,7 +18,6 @@ QT_BEGIN_NAMESPACE
class QFont;
class QPainterPathPrivate;
struct QPainterPathPrivateDeleter;
-class QPainterPathData;
class QPainterPathStrokerPrivate;
class QPen;
class QPolygonF;
@@ -93,8 +56,7 @@ public:
explicit QPainterPath(const QPointF &startPoint);
QPainterPath(const QPainterPath &other);
QPainterPath &operator=(const QPainterPath &other);
- inline QPainterPath &operator=(QPainterPath &&other) noexcept
- { qSwap(d_ptr, other.d_ptr); return *this; }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPainterPath)
~QPainterPath();
inline void swap(QPainterPath &other) noexcept { d_ptr.swap(other.d_ptr); }
@@ -151,8 +113,8 @@ public:
void translate(qreal dx, qreal dy);
inline void translate(const QPointF &offset);
- Q_REQUIRED_RESULT QPainterPath translated(qreal dx, qreal dy) const;
- Q_REQUIRED_RESULT inline QPainterPath translated(const QPointF &offset) const;
+ [[nodiscard]] QPainterPath translated(qreal dx, qreal dy) const;
+ [[nodiscard]] inline QPainterPath translated(const QPointF &offset) const;
QRectF boundingRect() const;
QRectF controlPointRect() const;
@@ -162,7 +124,7 @@ public:
bool isEmpty() const;
- Q_REQUIRED_RESULT QPainterPath toReversed() const;
+ [[nodiscard]] QPainterPath toReversed() const;
QList<QPolygonF> toSubpathPolygons(const QTransform &matrix = QTransform()) const;
QList<QPolygonF> toFillPolygons(const QTransform &matrix = QTransform()) const;
@@ -180,11 +142,11 @@ public:
bool intersects(const QPainterPath &p) const;
bool contains(const QPainterPath &p) const;
- Q_REQUIRED_RESULT QPainterPath united(const QPainterPath &r) const;
- Q_REQUIRED_RESULT QPainterPath intersected(const QPainterPath &r) const;
- Q_REQUIRED_RESULT QPainterPath subtracted(const QPainterPath &r) const;
+ [[nodiscard]] QPainterPath united(const QPainterPath &r) const;
+ [[nodiscard]] QPainterPath intersected(const QPainterPath &r) const;
+ [[nodiscard]] QPainterPath subtracted(const QPainterPath &r) const;
- Q_REQUIRED_RESULT QPainterPath simplified() const;
+ [[nodiscard]] QPainterPath simplified() const;
bool operator==(const QPainterPath &other) const;
bool operator!=(const QPainterPath &other) const;
@@ -199,19 +161,17 @@ public:
QPainterPath &operator-=(const QPainterPath &other);
private:
- QScopedPointer<QPainterPathPrivate, QPainterPathPrivateDeleter> d_ptr;
+ QExplicitlySharedDataPointer<QPainterPathPrivate> d_ptr;
inline void ensureData() { if (!d_ptr) ensureData_helper(); }
void ensureData_helper();
void detach();
- void detach_helper();
void setDirty(bool);
void computeBoundingRect() const;
void computeControlPointRect() const;
- QPainterPathData *d_func() const { return reinterpret_cast<QPainterPathData *>(d_ptr.data()); }
+ QPainterPathPrivate *d_func() const { return d_ptr.data(); }
- friend class QPainterPathData;
friend class QPainterPathStroker;
friend class QPainterPathStrokerPrivate;
friend class QTransform;
diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h
index 57668190db..a07b6cca37 100644
--- a/src/gui/painting/qpainterpath_p.h
+++ b/src/gui/painting/qpainterpath_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPAINTERPATH_P_H
#define QPAINTERPATH_P_H
@@ -55,6 +19,7 @@
#include "QtGui/qpainterpath.h"
#include "QtGui/qregion.h"
#include "QtCore/qlist.h"
+#include "QtCore/qshareddata.h"
#include "QtCore/qvarlengtharray.h"
#include <qdebug.h>
@@ -66,51 +31,6 @@
QT_BEGIN_NAMESPACE
-// ### Qt 6: merge with QPainterPathData
-class QPainterPathPrivate
-{
-public:
- friend class QPainterPath;
- friend class QPainterPathData;
- friend class QPainterPathStroker;
- friend class QPainterPathStrokerPrivate;
- friend class QTransform;
- friend class QVectorPath;
- friend struct QPainterPathPrivateDeleter;
-#ifndef QT_NO_DATASTREAM
- friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPainterPath &);
- friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPainterPath &);
-#endif
-
- QPainterPathPrivate() noexcept
- : ref(1)
- {
- }
-
- QPainterPathPrivate(const QPainterPathPrivate &other) noexcept
- : ref(1),
- elements(other.elements)
- {
- }
-
- QPainterPathPrivate &operator=(const QPainterPathPrivate &) = delete;
- ~QPainterPathPrivate() = default;
-
-private:
- QAtomicInt ref;
- QList<QPainterPath::Element> elements;
-};
-
-class QPainterPathStrokerPrivate
-{
-public:
- QPainterPathStrokerPrivate();
-
- QStroker stroker;
- QList<qfixed> dashPattern;
- qreal dashOffset;
-};
-
class QPolygonF;
class QVectorPathConverter;
@@ -173,36 +93,64 @@ private:
Q_DISABLE_COPY_MOVE(QVectorPathConverter)
};
-class QPainterPathData : public QPainterPathPrivate
+class QPainterPathPrivate : public QSharedData
{
public:
- QPainterPathData() :
- cStart(0),
- fillRule(Qt::OddEvenFill),
- require_moveTo(false),
- dirtyBounds(false),
- dirtyControlBounds(false),
- convex(false),
- pathConverter(nullptr)
+ friend class QPainterPath;
+ friend class QPainterPathStroker;
+ friend class QPainterPathStrokerPrivate;
+ friend class QTransform;
+ friend class QVectorPath;
+ friend struct QPainterPathPrivateDeleter;
+#ifndef QT_NO_DATASTREAM
+ friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPainterPath &);
+ friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPainterPath &);
+#endif
+
+ QPainterPathPrivate() noexcept
+ : QSharedData(),
+ cStart(0),
+ fillRule(Qt::OddEvenFill),
+ require_moveTo(false),
+ dirtyBounds(false),
+ dirtyControlBounds(false),
+ convex(false),
+ pathConverter(nullptr)
+ {
+ }
+
+ QPainterPathPrivate(QPointF startPoint)
+ : QSharedData(),
+ elements{ { startPoint.x(), startPoint.y(), QPainterPath::MoveToElement } },
+ cStart(0),
+ fillRule(Qt::OddEvenFill),
+ bounds(startPoint, QSizeF(0, 0)),
+ controlBounds(startPoint, QSizeF(0, 0)),
+ require_moveTo(false),
+ dirtyBounds(false),
+ dirtyControlBounds(false),
+ convex(false),
+ pathConverter(nullptr)
{
}
- QPainterPathData(const QPainterPathData &other) :
- QPainterPathPrivate(other),
- cStart(other.cStart),
- fillRule(other.fillRule),
- bounds(other.bounds),
- controlBounds(other.controlBounds),
- require_moveTo(false),
- dirtyBounds(other.dirtyBounds),
- dirtyControlBounds(other.dirtyControlBounds),
- convex(other.convex),
- pathConverter(nullptr)
+ QPainterPathPrivate(const QPainterPathPrivate &other) noexcept
+ : QSharedData(other),
+ elements(other.elements),
+ cStart(other.cStart),
+ fillRule(other.fillRule),
+ bounds(other.bounds),
+ controlBounds(other.controlBounds),
+ require_moveTo(false),
+ dirtyBounds(other.dirtyBounds),
+ dirtyControlBounds(other.dirtyControlBounds),
+ convex(other.convex),
+ pathConverter(nullptr)
{
}
- QPainterPathData &operator=(const QPainterPathData &) = delete;
- ~QPainterPathData() = default;
+ QPainterPathPrivate &operator=(const QPainterPathPrivate &) = delete;
+ ~QPainterPathPrivate() = default;
inline bool isClosed() const;
inline void close();
@@ -215,6 +163,9 @@ public:
return pathConverter->path;
}
+private:
+ QList<QPainterPath::Element> elements;
+
int cStart;
Qt::FillRule fillRule;
@@ -229,12 +180,21 @@ public:
std::unique_ptr<QVectorPathConverter> pathConverter;
};
+class QPainterPathStrokerPrivate
+{
+public:
+ QPainterPathStrokerPrivate();
+
+ QStroker stroker;
+ QList<qfixed> dashPattern;
+ qreal dashOffset;
+};
inline const QPainterPath QVectorPath::convertToPainterPath() const
{
QPainterPath path;
path.ensureData();
- QPainterPathData *data = path.d_func();
+ QPainterPathPrivate *data = path.d_func();
data->elements.reserve(m_count);
int index = 0;
data->elements[0].x = m_points[index++];
@@ -270,14 +230,14 @@ inline const QPainterPath QVectorPath::convertToPainterPath() const
void Q_GUI_EXPORT qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
QPointF* startPoint, QPointF *endPoint);
-inline bool QPainterPathData::isClosed() const
+inline bool QPainterPathPrivate::isClosed() const
{
const QPainterPath::Element &first = elements.at(cStart);
const QPainterPath::Element &last = elements.last();
return first.x == last.x && first.y == last.y;
}
-inline void QPainterPathData::close()
+inline void QPainterPathPrivate::close()
{
Q_ASSERT(ref.loadRelaxed() == 1);
require_moveTo = true;
@@ -294,7 +254,7 @@ inline void QPainterPathData::close()
}
}
-inline void QPainterPathData::maybeMoveTo()
+inline void QPainterPathPrivate::maybeMoveTo()
{
if (require_moveTo) {
QPainterPath::Element e = elements.last();
@@ -304,14 +264,13 @@ inline void QPainterPathData::maybeMoveTo()
}
}
-inline void QPainterPathData::clear()
+inline void QPainterPathPrivate::clear()
{
Q_ASSERT(ref.loadRelaxed() == 1);
elements.clear();
cStart = 0;
- fillRule = Qt::OddEvenFill;
bounds = {};
controlBounds = {};
diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp
index 2fbf8bdcba..10a0639b53 100644
--- a/src/gui/painting/qpathclipper.cpp
+++ b/src/gui/painting/qpathclipper.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpathclipper_p.h"
@@ -99,6 +63,7 @@ struct QIntersection
QPointF pos;
};
+Q_DECLARE_TYPEINFO(QIntersection, Q_PRIMITIVE_TYPE);
class QIntersectionFinder
{
@@ -268,11 +233,11 @@ private:
void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);
QPathSegments &m_segments;
- QVector<int> m_index;
+ QList<int> m_index;
RectF m_bounds;
- QVector<TreeNode> m_tree;
+ QList<TreeNode> m_tree;
QDataBuffer<QIntersection> m_intersections;
};
@@ -685,7 +650,8 @@ int QKdPointTree::build(int begin, int end, int depth)
}
}
- qSwap(m_nodes.at(last), m_nodes.at(begin));
+ if (last != begin)
+ qSwap(m_nodes.at(last), m_nodes.at(begin));
if (last > begin)
m_nodes.at(last).left = &m_nodes.at(build(begin, last, depth + 1));
@@ -1618,7 +1584,7 @@ QPainterPath QPathClipper::clip(Operation operation)
bool QPathClipper::doClip(QWingedEdge &list, ClipperMode mode)
{
- QVector<qreal> y_coords;
+ QList<qreal> y_coords;
y_coords.reserve(list.vertexCount());
for (int i = 0; i < list.vertexCount(); ++i)
y_coords << list.vertex(i)->y;
@@ -1778,9 +1744,9 @@ bool QWingedEdge::isInside(qreal x, qreal y) const
return winding & 1;
}
-static QVector<QCrossingEdge> findCrossings(const QWingedEdge &list, qreal y)
+static QList<QCrossingEdge> findCrossings(const QWingedEdge &list, qreal y)
{
- QVector<QCrossingEdge> crossings;
+ QList<QCrossingEdge> crossings;
for (int i = 0; i < list.edgeCount(); ++i) {
const QPathEdge *edge = list.edge(i);
QPointF a = *list.vertex(edge->first);
@@ -1797,7 +1763,7 @@ static QVector<QCrossingEdge> findCrossings(const QWingedEdge &list, qreal y)
bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode)
{
- QVector<QCrossingEdge> crossings = findCrossings(list, y);
+ QList<QCrossingEdge> crossings = findCrossings(list, y);
Q_ASSERT(!crossings.isEmpty());
std::sort(crossings.begin(), crossings.end());
@@ -1869,10 +1835,10 @@ bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode m
namespace {
-QVector<QPainterPath> toSubpaths(const QPainterPath &path)
+QList<QPainterPath> toSubpaths(const QPainterPath &path)
{
- QVector<QPainterPath> subpaths;
+ QList<QPainterPath> subpaths;
if (path.isEmpty())
return subpaths;
@@ -1965,7 +1931,7 @@ void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result)
if (outA)
addLine(result, QLineF(intersectLine<edge>(a, b, t), b));
- else if(outB)
+ else if (outB)
addLine(result, QLineF(a, intersectLine<edge>(a, b, t)));
else
addLine(result, QLineF(a, b));
@@ -2072,7 +2038,7 @@ QPainterPath clip(const QPainterPath &path, qreal t)
QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect)
{
- QVector<QPainterPath> subpaths = toSubpaths(path);
+ QList<QPainterPath> subpaths = toSubpaths(path);
QPainterPath result;
result.setFillRule(path.fillRule());
diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h
index 6f712c396e..f13b96e0ef 100644
--- a/src/gui/painting/qpathclipper_p.h
+++ b/src/gui/painting/qpathclipper_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPATHCLIPPER_P_H
#define QPATHCLIPPER_P_H
@@ -115,6 +79,7 @@ public:
qreal x;
qreal y;
};
+Q_DECLARE_TYPEINFO(QPathVertex, Q_PRIMITIVE_TYPE);
class QPathEdge
{
@@ -156,8 +121,9 @@ public:
int vertex(Direction direction) const;
private:
- int m_next[2][2];
+ int m_next[2][2] = { { -1, -1 }, { -1, -1 } };
};
+Q_DECLARE_TYPEINFO(QPathEdge, Q_PRIMITIVE_TYPE);
class QPathSegments
{
@@ -171,6 +137,7 @@ public:
return t < o.t;
}
};
+ friend class QTypeInfo<Intersection>;
struct Segment {
Segment(int pathId, int vertexA, int vertexB)
@@ -192,6 +159,7 @@ public:
QRectF bounds;
};
+ friend class QTypeInfo<Segment>;
QPathSegments(int reserve);
@@ -223,6 +191,8 @@ private:
int m_pathId;
};
+Q_DECLARE_TYPEINFO(QPathSegments::Intersection, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QPathSegments::Segment, Q_PRIMITIVE_TYPE);
class Q_AUTOTEST_EXPORT QWingedEdge
{
@@ -296,10 +266,6 @@ inline QPathEdge::QPathEdge(int a, int b)
, angle(0)
, invAngle(0)
{
- m_next[0][0] = -1;
- m_next[1][0] = -1;
- m_next[0][0] = -1;
- m_next[1][0] = -1;
}
inline int QPathEdge::next(Traversal traversal, Direction direction) const
diff --git a/src/gui/painting/qpathsimplifier.cpp b/src/gui/painting/qpathsimplifier.cpp
index 256a2fefe7..969308f0bb 100644
--- a/src/gui/painting/qpathsimplifier.cpp
+++ b/src/gui/painting/qpathsimplifier.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpathsimplifier_p.h"
@@ -44,7 +8,9 @@
#include <QtCore/qpoint.h>
#include <QtCore/qalgorithms.h>
-#include <private/qopengl_p.h>
+#if QT_CONFIG(opengl)
+# include <private/qopengl_p.h>
+#endif
#include <private/qrbtree_p.h>
QT_BEGIN_NAMESPACE
@@ -339,6 +305,7 @@ private:
Type type;
Element *element;
};
+ friend class QTypeInfo<Event>;
typedef QRBTree<Element *>::Node RBNode;
typedef BoundingVolumeHierarchy::Node BVHNode;
@@ -377,6 +344,10 @@ private:
uint m_hints;
};
+} // unnamed namespace
+
+Q_DECLARE_TYPEINFO(PathSimplifier::Event, Q_PRIMITIVE_TYPE);
+
inline PathSimplifier::BoundingVolumeHierarchy::BoundingVolumeHierarchy()
: root(nullptr)
, nodeBlock(nullptr)
@@ -880,9 +851,9 @@ void PathSimplifier::connectElements()
#ifndef QT_NO_DEBUG
for (int i = 0; i < m_elements.size(); ++i) {
const Element *element = m_elements.at(i);
- Q_ASSERT(element->next == 0 || element->next->previous == element);
- Q_ASSERT(element->previous == 0 || element->previous->next == element);
- Q_ASSERT((element->next == 0) == (element->previous == 0));
+ Q_ASSERT(element->next == nullptr || element->next->previous == element);
+ Q_ASSERT(element->previous == nullptr || element->previous->next == element);
+ Q_ASSERT((element->next == nullptr) == (element->previous == nullptr));
}
#endif
}
@@ -1442,7 +1413,7 @@ bool PathSimplifier::elementIsLeftOf(const Element *left, const Element *right)
QPair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerBounds(const QPoint &point)
{
RBNode *current = m_elementList.root;
- QPair<RBNode *, RBNode *> result(0, 0);
+ QPair<RBNode *, RBNode *> result(nullptr, nullptr);
while (current) {
const Element *element = current->data;
@@ -1650,9 +1621,6 @@ void PathSimplifier::sortEvents(Event *events, int count)
}
}
-} // end anonymous namespace
-
-
void qSimplifyPath(const QVectorPath &path, QDataBuffer<QPoint> &vertices,
QDataBuffer<quint32> &indices, const QTransform &matrix)
{
@@ -1667,3 +1635,5 @@ void qSimplifyPath(const QPainterPath &path, QDataBuffer<QPoint> &vertices,
QT_END_NAMESPACE
+
+#undef Q_FIXED_POINT_SCALE
diff --git a/src/gui/painting/qpathsimplifier_p.h b/src/gui/painting/qpathsimplifier_p.h
index 6c0062c592..b20b6370b3 100644
--- a/src/gui/painting/qpathsimplifier_p.h
+++ b/src/gui/painting/qpathsimplifier_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPATHSIMPLIFIER_P_H
#define QPATHSIMPLIFIER_P_H
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index de9fc13331..38f2a9b803 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpdf_p.h"
@@ -43,6 +7,7 @@
#include "qplatformdefs.h"
+#include <private/qcmyk_p.h>
#include <private/qfont_p.h>
#include <private/qmath_p.h>
#include <private/qpainter_p.h>
@@ -78,7 +43,9 @@ static void initResources()
QT_BEGIN_NAMESPACE
-inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
+using namespace Qt::StringLiterals;
+
+constexpr QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
{
QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures;
f &= ~(QPaintEngine::PorterDuff
@@ -133,7 +100,7 @@ static void removeTransparencyFromBrush(QBrush &brush)
const char *qt_real_to_string(qreal val, char *buf) {
const char *ret = buf;
- if (qIsNaN(val)) {
+ if (!qIsFinite(val) || std::abs(val) > std::numeric_limits<quint32>::max()) {
*(buf++) = '0';
*(buf++) = ' ';
*buf = 0;
@@ -144,8 +111,8 @@ const char *qt_real_to_string(qreal val, char *buf) {
*(buf++) = '-';
val = -val;
}
- unsigned int ival = (unsigned int) val;
- qreal frac = val - (qreal)ival;
+ qreal frac = std::modf(val, &val);
+ quint32 ival(val);
int ifrac = (int)(frac * 1000000000);
if (ifrac == 1000000000) {
@@ -304,13 +271,6 @@ namespace QPdf {
dev->open(QIODevice::ReadWrite | QIODevice::Truncate);
}
- void ByteStream::constructor_helper(QByteArray *ba)
- {
- delete dev;
- dev = new QBuffer(ba);
- dev->open(QIODevice::ReadWrite);
- }
-
void ByteStream::prepareBuffer()
{
Q_ASSERT(!dev->isSequential());
@@ -319,16 +279,17 @@ namespace QPdf {
&& size > maxMemorySize()) {
// Switch to file backing.
QTemporaryFile *newFile = new QTemporaryFile;
- newFile->open();
- dev->reset();
- while (!dev->atEnd()) {
- QByteArray buf = dev->read(chunkSize());
- newFile->write(buf);
+ if (newFile->open()) {
+ dev->reset();
+ while (!dev->atEnd()) {
+ QByteArray buf = dev->read(chunkSize());
+ newFile->write(buf);
+ }
+ delete dev;
+ dev = newFile;
+ ba.clear();
+ fileBackingActive = true;
}
- delete dev;
- dev = newFile;
- ba.clear();
- fileBackingActive = true;
}
if (dev->pos() != size) {
dev->seek(size);
@@ -421,7 +382,7 @@ QByteArray QPdf::generateDashes(const QPen &pen)
ByteStream s(&result);
s << '[';
- QVector<qreal> dasharray = pen.dashPattern();
+ QList<qreal> dasharray = pen.dashPattern();
qreal w = pen.widthF();
if (w < 0.001)
w = 1;
@@ -649,7 +610,7 @@ QPdf::Stroker::Stroker()
basicStroker.setStrokeWidth(.1);
}
-void QPdf::Stroker::setPen(const QPen &pen, QPainter::RenderHints hints)
+void QPdf::Stroker::setPen(const QPen &pen, QPainter::RenderHints)
{
if (pen.style() == Qt::NoPen) {
stroker = nullptr;
@@ -657,7 +618,7 @@ void QPdf::Stroker::setPen(const QPen &pen, QPainter::RenderHints hints)
}
qreal w = pen.widthF();
bool zeroWidth = w < 0.0001;
- cosmeticPen = qt_pen_is_cosmetic(pen, hints);
+ cosmeticPen = pen.isCosmetic();
if (zeroWidth)
w = .1;
@@ -666,7 +627,7 @@ void QPdf::Stroker::setPen(const QPen &pen, QPainter::RenderHints hints)
basicStroker.setJoinStyle(pen.joinStyle());
basicStroker.setMiterLimit(pen.miterLimit());
- QVector<qreal> dashpattern = pen.dashPattern();
+ QList<qreal> dashpattern = pen.dashPattern();
if (zeroWidth) {
for (int i = 0; i < dashpattern.size(); ++i)
dashpattern[i] *= 10.;
@@ -784,7 +745,7 @@ QPdfPage::QPdfPage()
{
}
-void QPdfPage::streamImage(int w, int h, int object)
+void QPdfPage::streamImage(int w, int h, uint object)
{
*this << w << "0 0 " << -h << "0 " << h << "cm /Im" << object << " Do\n";
if (!images.contains(object))
@@ -856,14 +817,14 @@ void QPdfEngine::drawRects (const QRectF *rects, int rectCount)
if (!d->hasPen && !d->hasBrush)
return;
- if (d->simplePen || !d->hasPen) {
- // draw strokes natively in this case for better output
- if(!d->simplePen && !d->stroker.matrix.isIdentity())
+ if ((d->simplePen && !d->needsTransform) || !d->hasPen) {
+ // draw natively in this case for better output
+ if (!d->hasPen && d->needsTransform) // i.e. this is just a fillrect
*d->currentPage << "q\n" << QPdf::generateMatrix(d->stroker.matrix);
for (int i = 0; i < rectCount; ++i)
*d->currentPage << rects[i].x() << rects[i].y() << rects[i].width() << rects[i].height() << "re\n";
*d->currentPage << (d->hasPen ? (d->hasBrush ? "B\n" : "S\n") : "f\n");
- if(!d->simplePen && !d->stroker.matrix.isIdentity())
+ if (!d->hasPen && d->needsTransform)
*d->currentPage << "Q\n";
} else {
QPainterPath p;
@@ -920,7 +881,8 @@ void QPdfEngine::drawPath (const QPainterPath &p)
if (d->simplePen) {
// draw strokes natively in this case for better output
- *d->currentPage << QPdf::generatePath(p, QTransform(), d->hasBrush ? QPdf::FillAndStrokePath : QPdf::StrokePath);
+ *d->currentPage << QPdf::generatePath(p, d->needsTransform ? d->stroker.matrix : QTransform(),
+ d->hasBrush ? QPdf::FillAndStrokePath : QPdf::StrokePath);
} else {
if (d->hasBrush)
*d->currentPage << QPdf::generatePath(p, d->stroker.matrix, QPdf::FillPath);
@@ -967,7 +929,7 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
- rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
+ rectangle.x(), rectangle.y()) * (!d->needsTransform ? QTransform() : d->stroker.matrix));
if (bitmap) {
// set current pen as d->brush
d->brush = d->pen.brush();
@@ -1007,7 +969,7 @@ void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const Q
*d->currentPage
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
- rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
+ rectangle.x(), rectangle.y()) * (!d->needsTransform ? QTransform() : d->stroker.matrix));
setBrush();
d->currentPage->streamImage(im.width(), im.height(), object);
*d->currentPage << "Q\n";
@@ -1056,7 +1018,7 @@ void QPdfEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
}
*d->currentPage << "q\n";
- if(!d->simplePen)
+ if (d->needsTransform)
*d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
bool hp = d->hasPen;
@@ -1114,6 +1076,9 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
QPaintEngine::DirtyFlags flags = state.state();
+ if (flags & DirtyHints)
+ flags |= DirtyBrush;
+
if (flags & DirtyTransform)
d->stroker.matrix = state.transform();
@@ -1135,12 +1100,12 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
d->pen = state.pen();
}
d->hasPen = d->pen.style() != Qt::NoPen;
+ bool oldCosmetic = d->stroker.cosmeticPen;
d->stroker.setPen(d->pen, state.renderHints());
QBrush penBrush = d->pen.brush();
- bool cosmeticPen = qt_pen_is_cosmetic(d->pen, state.renderHints());
bool oldSimple = d->simplePen;
- d->simplePen = (d->hasPen && !cosmeticPen && (penBrush.style() == Qt::SolidPattern) && penBrush.isOpaque() && d->opacity == 1.0);
- if (oldSimple != d->simplePen)
+ d->simplePen = (d->hasPen && (penBrush.style() == Qt::SolidPattern) && penBrush.isOpaque() && d->opacity == 1.0);
+ if (oldSimple != d->simplePen || oldCosmetic != d->stroker.cosmeticPen)
flags |= DirtyTransform;
} else if (flags & DirtyHints) {
d->stroker.setPen(d->pen, state.renderHints());
@@ -1224,8 +1189,13 @@ void QPdfEngine::setupGraphicsState(QPaintEngine::DirtyFlags flags)
if (flags & DirtyTransform) {
*d->currentPage << "q\n";
- if (d->simplePen && !d->stroker.matrix.isIdentity())
- *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
+ d->needsTransform = false;
+ if (!d->stroker.matrix.isIdentity()) {
+ if (d->simplePen && !d->stroker.cosmeticPen)
+ *d->currentPage << QPdf::generateMatrix(d->stroker.matrix);
+ else
+ d->needsTransform = true; // I.e. page-wide xf not set, local xf needed
+ }
}
if (flags & DirtyBrush)
setBrush();
@@ -1241,20 +1211,18 @@ void QPdfEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperation op)
QPainterPath path = d->stroker.matrix.map(p);
//qDebug() << "updateClipPath: " << d->stroker.matrix << p.boundingRect() << path.boundingRect() << op;
- if (op == Qt::NoClip) {
+ switch (op) {
+ case Qt::NoClip:
d->clipEnabled = false;
d->clips.clear();
- } else if (op == Qt::ReplaceClip) {
+ break;
+ case Qt::ReplaceClip:
d->clips.clear();
d->clips.append(path);
- } else if (op == Qt::IntersectClip) {
- d->clips.append(path);
- } else { // UniteClip
- // ask the painter for the current clipping path. that's the easiest solution
- path = painter()->clipPath();
- path = d->stroker.matrix.map(path);
- d->clips.clear();
+ break;
+ case Qt::IntersectClip:
d->clips.append(path);
+ break;
}
}
@@ -1266,17 +1234,8 @@ void QPdfEngine::setPen()
QBrush b = d->pen.brush();
Q_ASSERT(b.style() == Qt::SolidPattern && b.isOpaque());
- QColor rgba = b.color();
- if (d->grayscale) {
- qreal gray = qGray(rgba.rgba())/255.;
- *d->currentPage << gray << gray << gray;
- } else {
- *d->currentPage << rgba.redF()
- << rgba.greenF()
- << rgba.blueF();
- }
+ d->writeColor(QPdfEnginePrivate::ColorDomain::Stroking, b.color());
*d->currentPage << "SCN\n";
-
*d->currentPage << d->pen.widthF() << "w ";
int pdfCapStyle = 0;
@@ -1330,18 +1289,9 @@ void QPdfEngine::setBrush()
if (!patternObject && !specifyColor)
return;
- *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
- if (specifyColor) {
- QColor rgba = d->brush.color();
- if (d->grayscale) {
- qreal gray = qGray(rgba.rgba())/255.;
- *d->currentPage << gray << gray << gray;
- } else {
- *d->currentPage << rgba.redF()
- << rgba.greenF()
- << rgba.blueF();
- }
- }
+ const auto domain = patternObject ? QPdfEnginePrivate::ColorDomain::NonStrokingPattern
+ : QPdfEnginePrivate::ColorDomain::NonStroking;
+ d->writeColor(domain, specifyColor ? d->brush.color() : QColor());
if (patternObject)
*d->currentPage << "/Pat" << patternObject;
*d->currentPage << "scn\n";
@@ -1480,10 +1430,10 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
QPdfEnginePrivate::QPdfEnginePrivate()
: clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false),
- pdfVersion(QPdfEngine::Version_1_4),
+ needsTransform(false), pdfVersion(QPdfEngine::Version_1_4),
+ colorModel(QPdfEngine::ColorModel::Auto),
outDevice(nullptr), ownsDevice(false),
embedFonts(true),
- grayscale(false),
m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(10, 10, 10, 10))
{
initResources();
@@ -1532,13 +1482,17 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
d->xrefPositions.clear();
d->pageRoot = 0;
- d->embeddedfilesRoot = 0;
d->namesRoot = 0;
+ d->destsRoot = 0;
+ d->attachmentsRoot = 0;
d->catalog = 0;
d->info = 0;
d->graphicsState = 0;
- d->patternColorSpace = 0;
+ d->patternColorSpaceRGB = 0;
+ d->patternColorSpaceGrayscale = 0;
+ d->patternColorSpaceCMYK = 0;
d->simplePen = false;
+ d->needsTransform = false;
d->pages.clear();
d->imageCache.clear();
@@ -1569,6 +1523,7 @@ bool QPdfEngine::end()
d->outDevice = nullptr;
}
+ d->destCache.clear();
d->fileCache.clear();
setActive(false);
@@ -1617,10 +1572,7 @@ void QPdfEnginePrivate::writeHeader()
catalog = addXrefEntry(-1);
pageRoot = requestObject();
- if (!fileCache.isEmpty()) {
- namesRoot = requestObject();
- embeddedfilesRoot = requestObject();
- }
+ namesRoot = requestObject();
// catalog
{
@@ -1628,11 +1580,8 @@ void QPdfEnginePrivate::writeHeader()
QPdf::ByteStream s(&catalog);
s << "<<\n"
<< "/Type /Catalog\n"
- << "/Pages " << pageRoot << "0 R\n";
-
- // Embedded files, if any
- if (!fileCache.isEmpty())
- s << "/Names " << embeddedfilesRoot << "0 R\n";
+ << "/Pages " << pageRoot << "0 R\n"
+ << "/Names " << namesRoot << "0 R\n";
if (pdfVersion == QPdfEngine::Version_A1b || !xmpDocumentMetadata.isEmpty())
s << "/Metadata " << metaDataObj << "0 R\n";
@@ -1646,12 +1595,6 @@ void QPdfEnginePrivate::writeHeader()
write(catalog);
}
- if (!fileCache.isEmpty()) {
- addXrefEntry(embeddedfilesRoot);
- xprintf("<</EmbeddedFiles %d 0 R>>\n"
- "endobj\n", namesRoot);
- }
-
// graphics state
graphicsState = addXrefEntry(-1);
xprintf("<<\n"
@@ -1665,10 +1608,108 @@ void QPdfEnginePrivate::writeHeader()
">>\n"
"endobj\n");
- // color space for pattern
- patternColorSpace = addXrefEntry(-1);
+ // color spaces for pattern
+ patternColorSpaceRGB = addXrefEntry(-1);
xprintf("[/Pattern /DeviceRGB]\n"
"endobj\n");
+ patternColorSpaceGrayscale = addXrefEntry(-1);
+ xprintf("[/Pattern /DeviceGray]\n"
+ "endobj\n");
+ patternColorSpaceCMYK = addXrefEntry(-1);
+ xprintf("[/Pattern /DeviceCMYK]\n"
+ "endobj\n");
+}
+
+QPdfEngine::ColorModel QPdfEnginePrivate::colorModelForColor(const QColor &color) const
+{
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ case QPdfEngine::ColorModel::Grayscale:
+ case QPdfEngine::ColorModel::CMYK:
+ return colorModel;
+ case QPdfEngine::ColorModel::Auto:
+ switch (color.spec()) {
+ case QColor::Invalid:
+ case QColor::Rgb:
+ case QColor::Hsv:
+ case QColor::Hsl:
+ case QColor::ExtendedRgb:
+ return QPdfEngine::ColorModel::RGB;
+ case QColor::Cmyk:
+ return QPdfEngine::ColorModel::CMYK;
+ }
+
+ break;
+ }
+
+ Q_UNREACHABLE_RETURN(QPdfEngine::ColorModel::RGB);
+}
+
+void QPdfEnginePrivate::writeColor(ColorDomain domain, const QColor &color)
+{
+ // Switch to the right colorspace.
+ // For simplicity: do it even if it redundant (= already in that colorspace)
+ const QPdfEngine::ColorModel actualColorModel = colorModelForColor(color);
+
+ switch (actualColorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSp CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSp cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSp cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::Grayscale:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSpg CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSpg cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSpg cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::CMYK:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSpcmyk CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSpcmyk cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSpcmyk cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE_RETURN();
+ }
+
+ // If we also have a color specified, write it out.
+ if (!color.isValid())
+ return;
+
+ switch (actualColorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ *currentPage << color.redF()
+ << color.greenF()
+ << color.blueF();
+ break;
+ case QPdfEngine::ColorModel::Grayscale: {
+ const qreal gray = qGray(color.rgba()) / 255.;
+ *currentPage << gray;
+ break;
+ }
+ case QPdfEngine::ColorModel::CMYK:
+ *currentPage << color.cyanF()
+ << color.magentaF()
+ << color.yellowF()
+ << color.blackF();
+ break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE_RETURN();
+ }
}
void QPdfEnginePrivate::writeInfo()
@@ -1728,12 +1769,13 @@ int QPdfEnginePrivate::writeXmpDcumentMetaData()
else if (offset > 0)
tzStr = QString::asprintf("+%02d:%02d", hours , mins);
else
- tzStr = QLatin1String("Z");
+ tzStr = "Z"_L1;
const QString metaDataDate = timeStr + tzStr;
- QFile metaDataFile(QLatin1String(":/qpdf/qpdfa_metadata.xml"));
- metaDataFile.open(QIODevice::ReadOnly);
+ QFile metaDataFile(":/qpdf/qpdfa_metadata.xml"_L1);
+ bool ok = metaDataFile.open(QIODevice::ReadOnly);
+ Q_ASSERT(ok);
metaDataContent = QString::fromUtf8(metaDataFile.readAll()).arg(producer.toHtmlEscaped(),
title.toHtmlEscaped(),
creator.toHtmlEscaped(),
@@ -1758,8 +1800,9 @@ int QPdfEnginePrivate::writeOutputIntent()
{
const int colorProfile = addXrefEntry(-1);
{
- QFile colorProfileFile(QLatin1String(":/qpdf/sRGB2014.icc"));
- colorProfileFile.open(QIODevice::ReadOnly);
+ QFile colorProfileFile(":/qpdf/sRGB2014.icc"_L1);
+ bool ok = colorProfileFile.open(QIODevice::ReadOnly);
+ Q_ASSERT(ok);
const QByteArray colorProfileData = colorProfileFile.readAll();
QByteArray data;
@@ -1819,12 +1862,45 @@ void QPdfEnginePrivate::writePageRoot()
"endobj\n");
}
+void QPdfEnginePrivate::writeDestsRoot()
+{
+ if (destCache.isEmpty())
+ return;
+
+ QHash<QString, int> destObjects;
+ QByteArray xs, ys;
+ for (const DestInfo &destInfo : std::as_const(destCache)) {
+ int destObj = addXrefEntry(-1);
+ xs.setNum(static_cast<double>(destInfo.coords.x()), 'f');
+ ys.setNum(static_cast<double>(destInfo.coords.y()), 'f');
+ xprintf("[%d 0 R /XYZ %s %s 0]\n", destInfo.pageObj, xs.constData(), ys.constData());
+ xprintf("endobj\n");
+ destObjects.insert(destInfo.anchor, destObj);
+ }
+
+ // names
+ destsRoot = addXrefEntry(-1);
+ QStringList anchors = destObjects.keys();
+ anchors.sort();
+ xprintf("<<\n/Limits [");
+ printString(anchors.constFirst());
+ xprintf(" ");
+ printString(anchors.constLast());
+ xprintf("]\n/Names [\n");
+ for (const QString &anchor : std::as_const(anchors)) {
+ printString(anchor);
+ xprintf(" %d 0 R\n", destObjects[anchor]);
+ }
+ xprintf("]\n>>\n"
+ "endobj\n");
+}
+
void QPdfEnginePrivate::writeAttachmentRoot()
{
if (fileCache.isEmpty())
return;
- QVector<int> attachments;
+ QList<int> attachments;
const int size = fileCache.size();
for (int i = 0; i < size; ++i) {
auto attachment = fileCache.at(i);
@@ -1853,13 +1929,12 @@ void QPdfEnginePrivate::writeAttachmentRoot()
, attachmentID);
if (!attachment.mimeType.isEmpty())
xprintf("/Subtype/%s\n",
- attachment.mimeType.replace(QLatin1String("/"),
- QLatin1String("#2F")).toLatin1().constData());
+ attachment.mimeType.replace("/"_L1, "#2F"_L1).toLatin1().constData());
xprintf(">>\nendobj\n");
}
// names
- addXrefEntry(namesRoot);
+ attachmentsRoot = addXrefEntry(-1);
xprintf("<</Names[");
for (int i = 0; i < size; ++i) {
auto attachment = fileCache.at(i);
@@ -1870,6 +1945,21 @@ void QPdfEnginePrivate::writeAttachmentRoot()
"endobj\n");
}
+void QPdfEnginePrivate::writeNamesRoot()
+{
+ addXrefEntry(namesRoot);
+ xprintf("<<\n");
+
+ if (attachmentsRoot)
+ xprintf("/EmbeddedFiles %d 0 R\n", attachmentsRoot);
+
+ if (destsRoot)
+ xprintf("/Dests %d 0 R\n", destsRoot);
+
+ xprintf(">>\n");
+ xprintf("endobj\n");
+}
+
void QPdfEnginePrivate::embedFont(QFontSubset *font)
{
//qDebug() << "embedFont" << font->object_id;
@@ -1963,7 +2053,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
addXrefEntry(toUnicode);
QByteArray touc = font->createToUnicodeMap();
xprintf("<< /Length %d >>\n"
- "stream\n", touc.length());
+ "stream\n", touc.size());
write(touc);
write("\nendstream\n"
"endobj\n");
@@ -1986,7 +2076,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
QByteArray cidSetStream(font->nGlyphs() / 8 + 1, 0);
int byteCounter = 0;
int bitCounter = 0;
- for (int i = 0; i < font->nGlyphs(); ++i) {
+ for (qsizetype i = 0; i < font->nGlyphs(); ++i) {
cidSetStream.data()[byteCounter] |= (1 << (7 - bitCounter));
bitCounter++;
@@ -2067,12 +2157,18 @@ void QPdfEnginePrivate::writePage()
xprintf("<<\n"
"/ColorSpace <<\n"
"/PCSp %d 0 R\n"
+ "/PCSpg %d 0 R\n"
+ "/PCSpcmyk %d 0 R\n"
"/CSp /DeviceRGB\n"
"/CSpg /DeviceGray\n"
+ "/CSpcmyk /DeviceCMYK\n"
">>\n"
"/ExtGState <<\n"
"/GSa %d 0 R\n",
- patternColorSpace, graphicsState);
+ patternColorSpaceRGB,
+ patternColorSpaceGrayscale,
+ patternColorSpaceCMYK,
+ graphicsState);
for (int i = 0; i < currentPage->graphicStates.size(); ++i)
xprintf("/GState%d %d 0 R\n", currentPage->graphicStates.at(i), currentPage->graphicStates.at(i));
@@ -2126,7 +2222,9 @@ void QPdfEnginePrivate::writeTail()
writePage();
writeFonts();
writePageRoot();
+ writeDestsRoot();
writeAttachmentRoot();
+ writeNamesRoot();
addXrefEntry(xrefPositions.size(),false);
xprintf("xref\n"
@@ -2175,7 +2273,7 @@ int QPdfEnginePrivate::addXrefEntry(int object, bool printostr)
return object;
}
-void QPdfEnginePrivate::printString(const QString &string)
+void QPdfEnginePrivate::printString(QStringView string)
{
if (string.isEmpty()) {
write("()");
@@ -2186,9 +2284,9 @@ void QPdfEnginePrivate::printString(const QString &string)
// Unicode UTF-16 with a Unicode byte order mark as the first character
// (0xfeff), with the high-order byte first.
QByteArray array("(\xfe\xff");
- const ushort *utf16 = string.utf16();
+ const char16_t *utf16 = string.utf16();
- for (int i=0; i < string.size(); ++i) {
+ for (qsizetype i = 0; i < string.size(); ++i) {
char part[2] = {char((*(utf16 + i)) >> 8), char((*(utf16 + i)) & 0xff)};
for(int j=0; j < 2; ++j) {
if (part[j] == '(' || part[j] == ')' || part[j] == '\\')
@@ -2304,17 +2402,16 @@ int QPdfEnginePrivate::writeCompressed(QIODevice *dev)
int QPdfEnginePrivate::writeCompressed(const char *src, int len)
{
#ifndef QT_NO_COMPRESS
- if(do_compress) {
- uLongf destLen = len + len/100 + 13; // zlib requirement
- Bytef* dest = new Bytef[destLen];
- if (Z_OK == ::compress(dest, &destLen, (const Bytef*) src, (uLongf)len)) {
- stream->writeRawData((const char*)dest, destLen);
+ if (do_compress) {
+ const QByteArray data = qCompress(reinterpret_cast<const uchar *>(src), len);
+ constexpr qsizetype HeaderSize = 4;
+ if (!data.isNull()) {
+ stream->writeRawData(data.data() + HeaderSize, data.size() - HeaderSize);
+ len = data.size() - HeaderSize;
} else {
qWarning("QPdfStream::writeCompressed: Error in compress()");
- destLen = 0;
+ len = 0;
}
- delete [] dest;
- len = destLen;
} else
#endif
{
@@ -2324,7 +2421,7 @@ int QPdfEnginePrivate::writeCompressed(const char *src, int len)
return len;
}
-int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, int depth,
+int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, WriteImageOption option,
int maskObject, int softMaskObject, bool dct, bool isMono)
{
int image = addXrefEntry(-1);
@@ -2334,7 +2431,8 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
"/Width %d\n"
"/Height %d\n", width, height);
- if (depth == 1) {
+ switch (option) {
+ case WriteImageOption::Monochrome:
if (!isMono) {
xprintf("/ImageMask true\n"
"/Decode [1 0]\n");
@@ -2342,10 +2440,21 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
xprintf("/BitsPerComponent 1\n"
"/ColorSpace /DeviceGray\n");
}
- } else {
+ break;
+ case WriteImageOption::Grayscale:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceGray\n");
+ break;
+ case WriteImageOption::RGB:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceRGB\n");
+ break;
+ case WriteImageOption::CMYK:
xprintf("/BitsPerComponent 8\n"
- "/ColorSpace %s\n", (depth == 32) ? "/DeviceRGB" : "/DeviceGray");
+ "/ColorSpace /DeviceCMYK\n");
+ break;
}
+
if (maskObject > 0)
xprintf("/Mask %d 0 R\n", maskObject);
if (softMaskObject > 0)
@@ -2360,7 +2469,7 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
//qDebug("DCT");
xprintf("/Filter /DCTDecode\n>>\nstream\n");
write(data);
- len = data.length();
+ len = data.size();
} else {
if (do_compress)
xprintf("/Filter /FlateDecode\n>>\nstream\n");
@@ -2384,7 +2493,23 @@ struct QGradientBound {
};
Q_DECLARE_TYPEINFO(QGradientBound, Q_PRIMITIVE_TYPE);
-int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha)
+void QPdfEnginePrivate::ShadingFunctionResult::writeColorSpace(QPdf::ByteStream *stream) const
+{
+ *stream << "/ColorSpace ";
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ *stream << "/DeviceRGB\n"; break;
+ case QPdfEngine::ColorModel::Grayscale:
+ *stream << "/DeviceGray\n"; break;
+ case QPdfEngine::ColorModel::CMYK:
+ *stream << "/DeviceCMYK\n"; break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE(); break;
+ }
+}
+
+QPdfEnginePrivate::ShadingFunctionResult
+QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha)
{
QGradientStops stops = gradient->stops();
if (stops.isEmpty()) {
@@ -2396,7 +2521,36 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
if (stops.at(stops.size() - 1).first < 1)
stops.append(QGradientStop(1, stops.at(stops.size() - 1).second));
- QVector<int> functions;
+ // Color to use which colorspace to use
+ const QColor referenceColor = stops.constFirst().second;
+
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ case QPdfEngine::ColorModel::Grayscale:
+ case QPdfEngine::ColorModel::CMYK:
+ break;
+ case QPdfEngine::ColorModel::Auto: {
+ // Make sure that all the stops have the same color spec
+ // (we don't support anything else)
+ const QColor::Spec referenceSpec = referenceColor.spec();
+ bool warned = false;
+ for (QGradientStop &stop : stops) {
+ if (stop.second.spec() != referenceSpec) {
+ if (!warned) {
+ qWarning("QPdfEngine: unable to create a gradient between colors of different spec");
+ warned = true;
+ }
+ stop.second = stop.second.convertTo(referenceSpec);
+ }
+ }
+ break;
+ }
+ }
+
+ ShadingFunctionResult result;
+ result.colorModel = colorModelForColor(referenceColor);
+
+ QList<int> functions;
const int numStops = stops.size();
functions.reserve(numStops - 1);
for (int i = 0; i < numStops - 1; ++i) {
@@ -2411,8 +2565,31 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
s << "/C0 [" << stops.at(i).second.alphaF() << "]\n"
"/C1 [" << stops.at(i + 1).second.alphaF() << "]\n";
} else {
- s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n"
- "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n";
+ switch (result.colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n"
+ "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n";
+ break;
+ case QPdfEngine::ColorModel::Grayscale:
+ s << "/C0 [" << (qGray(stops.at(i).second.rgba()) / 255.) << "]\n"
+ "/C1 [" << (qGray(stops.at(i + 1).second.rgba()) / 255.) << "]\n";
+ break;
+ case QPdfEngine::ColorModel::CMYK:
+ s << "/C0 [" << stops.at(i).second.cyanF()
+ << stops.at(i).second.magentaF()
+ << stops.at(i).second.yellowF()
+ << stops.at(i).second.blackF() << "]\n"
+ "/C1 [" << stops.at(i + 1).second.cyanF()
+ << stops.at(i + 1).second.magentaF()
+ << stops.at(i + 1).second.yellowF()
+ << stops.at(i + 1).second.blackF() << "]\n";
+ break;
+
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE();
+ break;
+ }
+
}
s << ">>\n"
"endobj\n";
@@ -2420,7 +2597,7 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
functions << f;
}
- QVector<QGradientBound> gradientBounds;
+ QList<QGradientBound> gradientBounds;
gradientBounds.reserve((to - from) * (numStops - 1));
for (int step = from; step < to; ++step) {
@@ -2480,7 +2657,8 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
} else {
function = functions.at(0);
}
- return function;
+ result.function = function;
+ return result;
}
int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradient, const QTransform &matrix, bool alpha)
@@ -2526,17 +2704,22 @@ int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradi
}
}
- int function = createShadingFunction(gradient, from, to, reflect, alpha);
+ const auto shadingFunctionResult = createShadingFunction(gradient, from, to, reflect, alpha);
QByteArray shader;
QPdf::ByteStream s(&shader);
s << "<<\n"
- "/ShadingType 2\n"
- "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") <<
- "/AntiAlias true\n"
+ "/ShadingType 2\n";
+
+ if (alpha)
+ s << "/ColorSpace /DeviceGray\n";
+ else
+ shadingFunctionResult.writeColorSpace(&s);
+
+ s << "/AntiAlias true\n"
"/Coords [" << start.x() << start.y() << stop.x() << stop.y() << "]\n"
"/Extend [true true]\n"
- "/Function " << function << "0 R\n"
+ "/Function " << shadingFunctionResult.function << "0 R\n"
">>\n"
"endobj\n";
int shaderObject = addXrefEntry(-1);
@@ -2594,18 +2777,23 @@ int QPdfEnginePrivate::generateRadialGradientShader(const QRadialGradient *gradi
}
}
- int function = createShadingFunction(gradient, from, to, reflect, alpha);
+ const auto shadingFunctionResult = createShadingFunction(gradient, from, to, reflect, alpha);
QByteArray shader;
QPdf::ByteStream s(&shader);
s << "<<\n"
- "/ShadingType 3\n"
- "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") <<
- "/AntiAlias true\n"
+ "/ShadingType 3\n";
+
+ if (alpha)
+ s << "/ColorSpace /DeviceGray\n";
+ else
+ shadingFunctionResult.writeColorSpace(&s);
+
+ s << "/AntiAlias true\n"
"/Domain [0 1]\n"
"/Coords [" << p0.x() << p0.y() << r0 << p1.x() << p1.y() << r1 << "]\n"
"/Extend [true true]\n"
- "/Function " << function << "0 R\n"
+ "/Function " << shadingFunctionResult.function << "0 R\n"
">>\n"
"endobj\n";
int shaderObject = addXrefEntry(-1);
@@ -2691,7 +2879,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix,
"/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n"
">>\n";
- f << "/Length " << content.length() << "\n"
+ f << "/Length " << content.size() << "\n"
">>\n"
"stream\n"
<< content
@@ -2714,7 +2902,7 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha)
{
if (brushAlpha == 255 && penAlpha == 255)
return 0;
- int object = alphaCache.value(QPair<uint, uint>(brushAlpha, penAlpha), 0);
+ uint object = alphaCache.value(QPair<uint, uint>(brushAlpha, penAlpha), 0);
if (!object) {
object = addXrefEntry(-1);
QByteArray alphaDef;
@@ -2742,17 +2930,23 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
*specifyColor = true;
*gStateObject = 0;
- QTransform matrix = m;
+ const Qt::BrushStyle style = brush.style();
+ const bool isCosmetic = style >= Qt::Dense1Pattern && style <= Qt::DiagCrossPattern
+ && !q->painter()->testRenderHint(QPainter::NonCosmeticBrushPatterns);
+ QTransform matrix;
+ if (!isCosmetic)
+ matrix = m;
matrix.translate(brushOrigin.x(), brushOrigin.y());
matrix = matrix * pageMatrix();
- //qDebug() << brushOrigin << matrix;
- Qt::BrushStyle style = brush.style();
if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) {
*specifyColor = false;
return gradientBrush(brush, matrix, gStateObject);
}
+ if (!isCosmetic)
+ matrix = brush.transform() * matrix;
+
if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0)
*gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity),
qRound(pen.color().alpha() * opacity));
@@ -2803,7 +2997,7 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
s << "/XObject << /Im" << imageObject << ' ' << imageObject << "0 R >> ";
}
s << ">>\n"
- "/Length " << pattern.length() << "\n"
+ "/Length " << pattern.size() << "\n"
">>\n"
"stream\n"
<< pattern
@@ -2816,7 +3010,7 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
return patternObj;
}
-static inline bool is_monochrome(const QVector<QRgb> &colorTable)
+static inline bool is_monochrome(const QList<QRgb> &colorTable)
{
return colorTable.size() == 2
&& colorTable.at(0) == QColor(Qt::black).rgba()
@@ -2833,11 +3027,12 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
return -1;
int object = imageCache.value(serial_no);
- if(object)
+ if (object)
return object;
QImage image = img;
QImage::Format format = image.format();
+ const bool grayscale = (colorModel == QPdfEngine::ColorModel::Grayscale);
if (pdfVersion == QPdfEngine::Version_A1b) {
if (image.hasAlphaChannel()) {
@@ -2861,7 +3056,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
format = QImage::Format_Mono;
} else {
*bitmap = false;
- if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32) {
+ if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32 && format != QImage::Format_CMYK8888) {
image = image.convertToFormat(QImage::Format_ARGB32);
format = QImage::Format_ARGB32;
}
@@ -2869,7 +3064,6 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
int w = image.width();
int h = image.height();
- int d = image.depth();
if (format == QImage::Format_Mono) {
int bytesPerLine = (w + 7) >> 3;
@@ -2880,7 +3074,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
memcpy(rawdata, image.constScanLine(y), bytesPerLine);
rawdata += bytesPerLine;
}
- object = writeImage(data, w, h, d, 0, 0, false, is_monochrome(img.colorTable()));
+ object = writeImage(data, w, h, WriteImageOption::Monochrome, 0, 0, false, is_monochrome(img.colorTable()));
} else {
QByteArray softMaskData;
bool dct = false;
@@ -2892,10 +3086,14 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
QBuffer buffer(&imageData);
QImageWriter writer(&buffer, "jpeg");
writer.setQuality(94);
+ if (format == QImage::Format_CMYK8888) {
+ // PDFs require CMYK colors not to be inverted in the JPEG encoding
+ writer.setSubType("CMYK");
+ }
writer.write(image);
dct = true;
- if (format != QImage::Format_RGB32) {
+ if (format != QImage::Format_RGB32 && format != QImage::Format_CMYK8888) {
softMaskData.resize(w * h);
uchar *sdata = (uchar *)softMaskData.data();
for (int y = 0; y < h; ++y) {
@@ -2910,41 +3108,59 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
}
}
} else {
- imageData.resize(grayscale ? w * h : 3 * w * h);
- uchar *data = (uchar *)imageData.data();
- softMaskData.resize(w * h);
- uchar *sdata = (uchar *)softMaskData.data();
- for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.constScanLine(y);
+ if (format == QImage::Format_CMYK8888) {
+ imageData.resize(grayscale ? w * h : w * h * 4);
+ uchar *data = (uchar *)imageData.data();
+ const qsizetype bytesPerLine = image.bytesPerLine();
if (grayscale) {
- for (int x = 0; x < w; ++x) {
- *(data++) = qGray(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
+ for (int y = 0; y < h; ++y) {
+ const uint *cmyk = (const uint *)image.constScanLine(y);
+ for (int x = 0; x < w; ++x)
+ *data++ = qGray(QCmyk32::fromCmyk32(*cmyk++).toColor().rgba());
}
} else {
- for (int x = 0; x < w; ++x) {
- *(data++) = qRed(*rgb);
- *(data++) = qGreen(*rgb);
- *(data++) = qBlue(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
+ for (int y = 0; y < h; ++y) {
+ uchar *start = data + y * w * 4;
+ memcpy(start, image.constScanLine(y), bytesPerLine);
+ }
+ }
+ } else {
+ imageData.resize(grayscale ? w * h : 3 * w * h);
+ uchar *data = (uchar *)imageData.data();
+ softMaskData.resize(w * h);
+ uchar *sdata = (uchar *)softMaskData.data();
+ for (int y = 0; y < h; ++y) {
+ const QRgb *rgb = (const QRgb *)image.constScanLine(y);
+ if (grayscale) {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qGray(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
+ } else {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qRed(*rgb);
+ *(data++) = qGreen(*rgb);
+ *(data++) = qBlue(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
}
}
}
- if (format == QImage::Format_RGB32)
+ if (format == QImage::Format_RGB32 || format == QImage::Format_CMYK8888)
hasAlpha = hasMask = false;
}
int maskObject = 0;
int softMaskObject = 0;
if (hasAlpha) {
- softMaskObject = writeImage(softMaskData, w, h, 8, 0, 0);
+ softMaskObject = writeImage(softMaskData, w, h, WriteImageOption::Grayscale, 0, 0);
} else if (hasMask) {
// dither the soft mask to 1bit and add it. This also helps PDF viewers
// without transparency support
@@ -2960,9 +3176,18 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
}
mdata += bytesPerLine;
}
- maskObject = writeImage(mask, w, h, 1, 0, 0);
+ maskObject = writeImage(mask, w, h, WriteImageOption::Monochrome, 0, 0);
}
- object = writeImage(imageData, w, h, grayscale ? 8 : 32,
+
+ const WriteImageOption option = [&]() {
+ if (grayscale)
+ return WriteImageOption::Grayscale;
+ if (format == QImage::Format_CMYK8888)
+ return WriteImageOption::CMYK;
+ return WriteImageOption::RGB;
+ }();
+
+ object = writeImage(imageData, w, h, option,
maskObject, softMaskObject, dct);
}
imageCache.insert(serial_no, object);
@@ -2973,7 +3198,9 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
{
Q_Q(QPdfEngine);
- if (ti.charFormat.isAnchor()) {
+ const bool isLink = ti.charFormat.hasProperty(QTextFormat::AnchorHref);
+ const bool isAnchor = ti.charFormat.hasProperty(QTextFormat::AnchorName);
+ if (isLink || isAnchor) {
qreal size = ti.fontEngine->fontDef.pixelSize;
int synthesized = ti.fontEngine->synthesized();
qreal stretch = synthesized & QFontEngine::SynthesizedStretch ? ti.fontEngine->fontDef.stretch/100. : 1.;
@@ -2993,32 +3220,47 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
trans.map(0, 0, &x1, &y1);
trans.map(ti.width.toReal()/size, (ti.ascent.toReal()-ti.descent.toReal())/size, &x2, &y2);
- uint annot = addXrefEntry(-1);
- QByteArray x1s, y1s, x2s, y2s;
- x1s.setNum(static_cast<double>(x1), 'f');
- y1s.setNum(static_cast<double>(y1), 'f');
- x2s.setNum(static_cast<double>(x2), 'f');
- y2s.setNum(static_cast<double>(y2), 'f');
- QByteArray rectData = x1s + ' ' + y1s + ' ' + x2s + ' ' + y2s;
- xprintf("<<\n/Type /Annot\n/Subtype /Link\n");
-
- if (pdfVersion == QPdfEngine::Version_A1b)
- xprintf("/F 4\n"); // enable print flag, disable all other
-
- xprintf("/Rect [");
- xprintf(rectData.constData());
+ if (isLink) {
+ uint annot = addXrefEntry(-1);
+ QByteArray x1s, y1s, x2s, y2s;
+ x1s.setNum(static_cast<double>(x1), 'f');
+ y1s.setNum(static_cast<double>(y1), 'f');
+ x2s.setNum(static_cast<double>(x2), 'f');
+ y2s.setNum(static_cast<double>(y2), 'f');
+ QByteArray rectData = x1s + ' ' + y1s + ' ' + x2s + ' ' + y2s;
+ xprintf("<<\n/Type /Annot\n/Subtype /Link\n");
+
+ if (pdfVersion == QPdfEngine::Version_A1b)
+ xprintf("/F 4\n"); // enable print flag, disable all other
+
+ xprintf("/Rect [");
+ xprintf(rectData.constData());
#ifdef Q_DEBUG_PDF_LINKS
- xprintf("]\n/Border [16 16 1]\n/A <<\n");
+ xprintf("]\n/Border [16 16 1]\n");
#else
- xprintf("]\n/Border [0 0 0]\n/A <<\n");
+ xprintf("]\n/Border [0 0 0]\n");
#endif
- xprintf("/Type /Action\n/S /URI\n/URI (%s)\n",
- ti.charFormat.anchorHref().toLatin1().constData());
- xprintf(">>\n>>\n");
- xprintf("endobj\n");
+ const QString link = ti.charFormat.anchorHref();
+ const bool isInternal = link.startsWith(QLatin1Char('#'));
+ if (!isInternal) {
+ xprintf("/A <<\n");
+ xprintf("/Type /Action\n/S /URI\n/URI (%s)\n", link.toLatin1().constData());
+ xprintf(">>\n");
+ } else {
+ xprintf("/Dest ");
+ printString(link.sliced(1));
+ xprintf("\n");
+ }
+ xprintf(">>\n");
+ xprintf("endobj\n");
- if (!currentPage->annotations.contains(annot)) {
- currentPage->annotations.append(annot);
+ if (!currentPage->annotations.contains(annot)) {
+ currentPage->annotations.append(annot);
+ }
+ } else {
+ const QString anchor = ti.charFormat.anchorNames().constFirst();
+ const uint curPage = pages.last();
+ destCache.append(DestInfo({ anchor, curPage, QPointF(x1, y2) }));
}
}
@@ -3038,7 +3280,7 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
noEmbed = true;
}
- QFontSubset *font = fonts.value(face_id, 0);
+ QFontSubset *font = fonts.value(face_id, nullptr);
if (!font) {
font = new QFontSubset(fe, requestObject());
font->noEmbed = noEmbed;
@@ -3100,7 +3342,7 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
x += .3*y;
x /= stretch;
char buf[5];
- int g = font->addGlyph(glyphs[i]);
+ qsizetype g = font->addGlyph(glyphs[i]);
*currentPage << x - last_x << last_y - y << "Td <"
<< QPdf::toHex((ushort)g, buf) << "> Tj\n";
last_x = x;
@@ -3120,7 +3362,7 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
x += .3*y;
x /= stretch;
char buf[5];
- int g = font->addGlyph(glyphs[i]);
+ qsizetype g = font->addGlyph(glyphs[i]);
*currentPage << x - last_x << last_y - y << "Td <"
<< QPdf::toHex((ushort)g, buf) << "> Tj\n";
last_x = x;
diff --git a/src/gui/painting/qpdf.qrc b/src/gui/painting/qpdf.qrc
deleted file mode 100644
index 56359c775b..0000000000
--- a/src/gui/painting/qpdf.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
- <qresource prefix="qpdf/">
- <file>qpdfa_metadata.xml</file>
- <file alias="sRGB2014.icc">../../3rdparty/icc/sRGB2014.icc</file>
- </qresource>
-</RCC>
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index c277539cfa..3c34e0bd7a 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPDF_P_H
#define QPDF_P_H
@@ -86,6 +50,8 @@ namespace QPdf {
ByteStream &operator <<(const ByteStream &src);
ByteStream &operator <<(qreal val);
ByteStream &operator <<(int val);
+ ByteStream &operator <<(uint val) { return (*this << int(val)); }
+ ByteStream &operator <<(qint64 val) { return (*this << int(val)); }
ByteStream &operator <<(const QPointF &p);
// Note that the stream may be invalidated by calls that insert data.
QIODevice *stream();
@@ -94,10 +60,6 @@ namespace QPdf {
static inline int maxMemorySize() { return 100000000; }
static inline int chunkSize() { return 10000000; }
- protected:
- void constructor_helper(QIODevice *dev);
- void constructor_helper(QByteArray *ba);
-
private:
void prepareBuffer();
@@ -153,7 +115,7 @@ public:
QList<uint> fonts;
QList<uint> annotations;
- void streamImage(int w, int h, int object);
+ void streamImage(int w, int h, uint object);
QSize pageSize;
private:
@@ -176,7 +138,7 @@ public:
};
QPdfEngine();
- QPdfEngine(QPdfEnginePrivate &d);
+ explicit QPdfEngine(QPdfEnginePrivate &d);
~QPdfEngine() {}
void setOutputFilename(const QString &filename);
@@ -191,6 +153,18 @@ public:
void addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType);
+ // keep in sync with QPdfWriter
+ enum class ColorModel
+ {
+ RGB,
+ Grayscale,
+ CMYK,
+ Auto,
+ };
+
+ ColorModel colorModel() const;
+ void setColorModel(ColorModel model);
+
// reimplementations QPaintEngine
bool begin(QPaintDevice *pdev) override;
bool end() override;
@@ -271,8 +245,10 @@ public:
bool hasPen;
bool hasBrush;
bool simplePen;
+ bool needsTransform;
qreal opacity;
QPdfEngine::PdfVersion pdfVersion;
+ QPdfEngine::ColorModel colorModel;
QHash<QFontEngine::FaceId, QFontSubset *> fonts;
@@ -288,7 +264,6 @@ public:
QString creator;
bool embedFonts;
int resolution;
- bool grayscale;
// Page layout: size, orientation and margins
QPageLayout m_pageLayout;
@@ -298,13 +273,29 @@ private:
int generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha = false);
int generateLinearGradientShader(const QLinearGradient *lg, const QTransform &matrix, bool alpha);
int generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha);
- int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha);
+ struct ShadingFunctionResult
+ {
+ int function;
+ QPdfEngine::ColorModel colorModel;
+ void writeColorSpace(QPdf::ByteStream *stream) const;
+ };
+ ShadingFunctionResult createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha);
+ enum class ColorDomain {
+ Stroking,
+ NonStroking,
+ NonStrokingPattern,
+ };
+
+ QPdfEngine::ColorModel colorModelForColor(const QColor &color) const;
+ void writeColor(ColorDomain domain, const QColor &color);
void writeInfo();
int writeXmpDcumentMetaData();
int writeOutputIntent();
void writePageRoot();
+ void writeDestsRoot();
void writeAttachmentRoot();
+ void writeNamesRoot();
void writeFonts();
void embedFont(QFontSubset *font);
qreal calcUserUnit() const;
@@ -313,12 +304,20 @@ private:
QDataStream* stream;
int streampos;
- int writeImage(const QByteArray &data, int width, int height, int depth,
+ enum class WriteImageOption
+ {
+ Monochrome,
+ Grayscale,
+ RGB,
+ CMYK,
+ };
+
+ int writeImage(const QByteArray &data, int width, int height, WriteImageOption option,
int maskObject, int softMaskObject, bool dct = false, bool isMono = false);
void writePage();
int addXrefEntry(int object, bool printostr = true);
- void printString(const QString &string);
+ void printString(QStringView string);
void xprintf(const char* fmt, ...);
inline void write(const QByteArray &data) {
stream->writeRawData(data.constData(), data.size());
@@ -326,7 +325,7 @@ private:
}
int writeCompressed(const char *src, int len);
- inline int writeCompressed(const QByteArray &data) { return writeCompressed(data.constData(), data.length()); }
+ inline int writeCompressed(const QByteArray &data) { return writeCompressed(data.constData(), data.size()); }
int writeCompressed(QIODevice *dev);
struct AttachmentInfo
@@ -338,11 +337,23 @@ private:
QString mimeType;
};
+ struct DestInfo
+ {
+ QString anchor;
+ uint pageObj;
+ QPointF coords;
+ };
+
// various PDF objects
- int pageRoot, embeddedfilesRoot, namesRoot, catalog, info, graphicsState, patternColorSpace;
+ int pageRoot, namesRoot, destsRoot, attachmentsRoot, catalog, info;
+ int graphicsState;
+ int patternColorSpaceRGB;
+ int patternColorSpaceGrayscale;
+ int patternColorSpaceCMYK;
QList<uint> pages;
QHash<qint64, uint> imageCache;
QHash<QPair<uint, uint>, uint > alphaCache;
+ QList<DestInfo> destCache;
QList<AttachmentInfo> fileCache;
QByteArray xmpDocumentMetadata;
};
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index 32f2194da3..bce65927ab 100644
--- a/src/gui/painting/qpdfwriter.cpp
+++ b/src/gui/painting/qpdfwriter.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qpdfwriter.h>
@@ -310,183 +274,76 @@ void QPdfWriter::addFileAttachment(const QString &fileName, const QByteArray &da
d->engine->addFileAttachment(fileName, data, mimeType);
}
-// Defined in QPagedPaintDevice but non-virtual, add QPdfWriter specific doc here
-#ifdef Q_QDOC
/*!
- \fn bool QPdfWriter::setPageLayout(const QPageLayout &newPageLayout)
- \since 5.3
-
- Sets the PDF page layout to \a newPageLayout.
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new page layout to a new page.
- You should not call any painting methods between a call to setPageLayout()
- and newPage() as the wrong paint metrics may be used.
-
- Returns true if the page layout was successfully set to \a newPageLayout.
-
- \sa pageLayout()
-*/
-
-/*!
- \fn bool QPdfWriter::setPageSize(const QPageSize &pageSize)
- \since 5.3
-
- Sets the PDF page size to \a pageSize.
-
- To get the current QPageSize use pageLayout().pageSize().
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new page size to a new page.
- You should not call any painting methods between a call to setPageSize()
- and newPage() as the wrong paint metrics may be used.
-
- Returns true if the page size was successfully set to \a pageSize.
-
- \sa pageLayout()
-*/
-
-/*!
- \fn bool QPdfWriter::setPageOrientation(QPageLayout::Orientation orientation)
- \since 5.3
-
- Sets the PDF page \a orientation.
-
- The page orientation is used to define the orientation of the
- page size when obtaining the page rect.
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new orientation to a new page.
- You should not call any painting methods between a call to setPageOrientation()
- and newPage() as the wrong paint metrics may be used.
-
- To get the current QPageLayout::Orientation use pageLayout().pageOrientation().
-
- Returns true if the page orientation was successfully set to \a orientation.
-
- \sa pageLayout()
-*/
-
-/*!
- \fn bool QPdfWriter::setPageMargins(const QMarginsF &margins)
- \since 5.3
-
- Set the PDF page \a margins in the current page layout units.
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new margins to a new page.
- You should not call any painting methods between a call to setPageMargins()
- and newPage() as the wrong paint metrics may be used.
-
- To get the current page margins use pageLayout().pageMargins().
-
- Returns true if the page margins were successfully set to \a margins.
+ \internal
- \sa pageLayout()
+ Returns the metric for the given \a id.
*/
+int QPdfWriter::metric(PaintDeviceMetric id) const
+{
+ Q_D(const QPdfWriter);
+ return d->engine->metric(id);
+}
/*!
- \fn bool QPdfWriter::setPageMargins(const QMarginsF &margins, QPageLayout::Unit units)
- \since 5.3
-
- Set the PDF page \a margins defined in the given \a units.
-
- You should call this before calling QPainter::begin(), or immediately
- before calling newPage() to apply the new margins to a new page.
- You should not call any painting methods between a call to setPageMargins()
- and newPage() as the wrong paint metrics may be used.
-
- To get the current page margins use pageLayout().pageMargins().
-
- Returns true if the page margins were successfully set to \a margins.
-
- \sa pageLayout()
+ \reimp
*/
+bool QPdfWriter::newPage()
+{
+ Q_D(QPdfWriter);
-/*!
- \fn QPageLayout QPdfWriter::pageLayout() const
- \since 5.3
-
- Returns the current page layout. Use this method to access the current
- QPageSize, QPageLayout::Orientation, QMarginsF, fullRect() and paintRect().
-
- Note that you cannot use the setters on the returned object, you must either
- call the individual QPdfWriter methods or use setPageLayout().
-
- \sa setPageLayout(), setPageSize(), setPageOrientation(), setPageMargins()
-*/
-#endif
+ return d->engine->newPage();
+}
-#if QT_DEPRECATED_SINCE(5, 14)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
/*!
- \reimp
+ \enum QPdfWriter::ColorModel
+ \since 6.8
- \obsolete Use setPageSize(QPageSize(id)) instead
+ This enumeration describes the way in which the PDF engine interprets
+ stroking and filling colors, set as a QPainter's pen or brush (via
+ QPen and QBrush).
- \sa setPageSize()
-*/
+ \value RGB All colors are converted to RGB and saved as such in the
+ PDF.
-void QPdfWriter::setPageSize(PageSize size)
-{
- setPageSize(QPageSize(QPageSize::PageSizeId(size)));
-}
+ \value Grayscale All colors are converted to grayscale. For backwards
+ compatibility, they are emitted in the PDF output as RGB colors, with
+ identical quantities of red, green and blue.
-/*!
- \reimp
+ \value CMYK All colors are converted to CMYK and saved as such.
- \obsolete Use setPageSize(QPageSize(size, QPageSize::Millimeter)) instead
+ \value Auto RGB colors are emitted as RGB; CMYK colors are emitted as
+ CMYK. Colors of any other color spec are converted to RGB.
+ This is the default since Qt 6.8.
- \sa setPageSize()
+ \sa QColor, QGradient
*/
-void QPdfWriter::setPageSizeMM(const QSizeF &size)
-{
- setPageSize(QPageSize(size, QPageSize::Millimeter));
-}
-QT_WARNING_POP
-#endif
-
/*!
- \internal
+ \since 6.8
- Returns the metric for the given \a id.
+ Returns the color model used by this PDF writer.
+ The default is QPdfWriter::ColorModel::Auto.
*/
-int QPdfWriter::metric(PaintDeviceMetric id) const
+QPdfWriter::ColorModel QPdfWriter::colorModel() const
{
Q_D(const QPdfWriter);
- return d->engine->metric(id);
+ return static_cast<ColorModel>(d->engine->d_func()->colorModel);
}
/*!
- \reimp
+ \since 6.8
+
+ Sets the color model used by this PDF writer to \a model.
*/
-bool QPdfWriter::newPage()
+void QPdfWriter::setColorModel(ColorModel model)
{
Q_D(QPdfWriter);
-
- return d->engine->newPage();
-}
-
-
-#if QT_DEPRECATED_SINCE(5, 14)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
-/*!
- \reimp
-
- \obsolete Use setPageMargins(QMarginsF(l, t, r, b), QPageLayout::Millimeter) instead
-
- \sa setPageMargins()
- */
-void QPdfWriter::setMargins(const Margins &m)
-{
- setPageMargins(QMarginsF(m.left, m.top, m.right, m.bottom), QPageLayout::Millimeter);
+ d->engine->d_func()->colorModel = static_cast<QPdfEngine::ColorModel>(model);
}
-QT_WARNING_POP
-#endif
QT_END_NAMESPACE
+#include "moc_qpdfwriter.cpp"
+
#endif // QT_NO_PDF
diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h
index 04039a0104..1a4b607b66 100644
--- a/src/gui/painting/qpdfwriter.h
+++ b/src/gui/painting/qpdfwriter.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPDFWRITER_H
#define QPDFWRITER_H
@@ -80,25 +44,17 @@ public:
void addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType = QString());
-#ifdef Q_QDOC
- bool setPageLayout(const QPageLayout &pageLayout);
- bool setPageSize(const QPageSize &pageSize);
- bool setPageOrientation(QPageLayout::Orientation orientation);
- bool setPageMargins(const QMarginsF &margins);
- bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units);
- QPageLayout pageLayout() const;
-#else
- using QPagedPaintDevice::setPageSize;
-#endif
-
-#if QT_DEPRECATED_SINCE(5, 14)
- QT_DEPRECATED_X("Use setPageSize(QPageSize(id)) instead")
- void setPageSize(PageSize size) override;
- QT_DEPRECATED_X("Use setPageSize(QPageSize(size, QPageSize::Millimeter)) instead")
- void setPageSizeMM(const QSizeF &size) override;
- QT_DEPRECATED_X("Use setPageMargins(QMarginsF(l, t, r, b), QPageLayout::Millimeter) instead")
- void setMargins(const Margins &m) override;
-#endif
+ enum class ColorModel
+ {
+ RGB,
+ Grayscale,
+ CMYK,
+ Auto,
+ };
+ Q_ENUM(ColorModel)
+
+ ColorModel colorModel() const;
+ void setColorModel(ColorModel model);
protected:
QPaintEngine *paintEngine() const override;
diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp
index 01e581d2ed..d37beda6b6 100644
--- a/src/gui/painting/qpen.cpp
+++ b/src/gui/painting/qpen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpen.h"
#include "qpen_p.h"
#include "qdatastream.h"
@@ -46,8 +10,6 @@
QT_BEGIN_NAMESPACE
-typedef QPenPrivate QPenData;
-
/*!
\class QPen
\inmodule QtGui
@@ -129,7 +91,7 @@ typedef QPenPrivate QPenData;
Since Qt 4.1 it is also possible to specify a custom dash pattern
using the setDashPattern() function which implicitly converts the
style of the pen to Qt::CustomDashLine. The pattern argument, a
- QVector, must be specified as an even number of \l qreal entries
+ QList, must be specified as an even number of \l qreal entries
where the entries 1, 3, 5... are the dashes and 2, 4, 6... are the
spaces. For example, the custom pattern shown above is created
using the following code:
@@ -227,10 +189,10 @@ typedef QPenPrivate QPenData;
/*!
\internal
*/
-inline QPenPrivate::QPenPrivate(const QBrush &_brush, qreal _width, Qt::PenStyle penStyle,
- Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle, bool _defaultWidth)
- : ref(1), dashOffset(0), miterLimit(2),
- cosmetic(false), defaultWidth(_defaultWidth)
+QPenPrivate::QPenPrivate(const QBrush &_brush, qreal _width, Qt::PenStyle penStyle,
+ Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle)
+ : dashOffset(0), miterLimit(2),
+ cosmetic(false)
{
width = _width;
brush = _brush;
@@ -245,17 +207,13 @@ static const Qt::PenJoinStyle qpen_default_join = Qt::BevelJoin;
class QPenDataHolder
{
public:
- QPenData *pen;
+ QPen::DataPtr pen;
QPenDataHolder(const QBrush &brush, qreal width, Qt::PenStyle penStyle,
Qt::PenCapStyle penCapStyle, Qt::PenJoinStyle _joinStyle)
- : pen(new QPenData(brush, width, penStyle, penCapStyle, _joinStyle))
+ : pen(new QPenPrivate(brush, width, penStyle, penCapStyle, _joinStyle))
{ }
- ~QPenDataHolder()
- {
- if (!pen->ref.deref())
- delete pen;
- pen = nullptr;
- }
+ ~QPenDataHolder() = default;
+ Q_DISABLE_COPY_MOVE(QPenDataHolder)
};
Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, defaultPenInstance,
@@ -270,7 +228,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, nullPenInstance,
QPen::QPen()
{
d = defaultPenInstance()->pen;
- d->ref.ref();
}
/*!
@@ -283,9 +240,8 @@ QPen::QPen(Qt::PenStyle style)
{
if (style == Qt::NoPen) {
d = nullPenInstance()->pen;
- d->ref.ref();
} else {
- d = new QPenData(Qt::black, 1, style, qpen_default_cap, qpen_default_join);
+ d = new QPenPrivate(Qt::black, 1, style, qpen_default_cap, qpen_default_join);
}
}
@@ -298,7 +254,7 @@ QPen::QPen(Qt::PenStyle style)
QPen::QPen(const QColor &color)
{
- d = new QPenData(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join);
+ d = new QPenPrivate(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join);
}
@@ -313,7 +269,7 @@ QPen::QPen(const QColor &color)
QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c, Qt::PenJoinStyle j)
{
- d = new QPenData(brush, width, s, c, j, false);
+ d = new QPenPrivate(brush, width, s, c, j);
}
/*!
@@ -323,10 +279,8 @@ QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c,
*/
QPen::QPen(const QPen &p) noexcept
+ : d(p.d)
{
- d = p.d;
- if (d)
- d->ref.ref();
}
@@ -345,11 +299,9 @@ QPen::QPen(const QPen &p) noexcept
Destroys the pen.
*/
-QPen::~QPen()
-{
- if (d && !d->ref.deref())
- delete d;
-}
+QPen::~QPen() = default;
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPenPrivate)
/*!
\fn void QPen::detach()
@@ -363,14 +315,7 @@ QPen::~QPen()
void QPen::detach()
{
- if (d->ref.loadRelaxed() == 1)
- return;
-
- QPenData *x = new QPenData(*static_cast<QPenData *>(d));
- if (!d->ref.deref())
- delete d;
- x->ref.storeRelaxed(1);
- d = x;
+ d.detach();
}
@@ -408,7 +353,7 @@ QPen &QPen::operator=(const QPen &p) noexcept
*/
QPen::operator QVariant() const
{
- return QVariant(QMetaType::QPen, this);
+ return QVariant::fromValue(*this);
}
/*!
@@ -443,9 +388,8 @@ void QPen::setStyle(Qt::PenStyle s)
return;
detach();
d->style = s;
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashPattern.clear();
- dd->dashOffset = 0;
+ d->dashPattern.clear();
+ d->dashOffset = 0;
}
/*!
@@ -453,38 +397,37 @@ void QPen::setStyle(Qt::PenStyle s)
\sa style(), isSolid()
*/
-QVector<qreal> QPen::dashPattern() const
+QList<qreal> QPen::dashPattern() const
{
- QPenData *dd = static_cast<QPenData *>(d);
if (d->style == Qt::SolidLine || d->style == Qt::NoPen) {
- return QVector<qreal>();
- } else if (dd->dashPattern.isEmpty()) {
+ return QList<qreal>();
+ } else if (d->dashPattern.isEmpty()) {
const qreal space = 2;
const qreal dot = 1;
const qreal dash = 4;
switch (d->style) {
case Qt::DashLine:
- dd->dashPattern.reserve(2);
- dd->dashPattern << dash << space;
+ d->dashPattern.reserve(2);
+ d->dashPattern << dash << space;
break;
case Qt::DotLine:
- dd->dashPattern.reserve(2);
- dd->dashPattern << dot << space;
+ d->dashPattern.reserve(2);
+ d->dashPattern << dot << space;
break;
case Qt::DashDotLine:
- dd->dashPattern.reserve(4);
- dd->dashPattern << dash << space << dot << space;
+ d->dashPattern.reserve(4);
+ d->dashPattern << dash << space << dot << space;
break;
case Qt::DashDotDotLine:
- dd->dashPattern.reserve(6);
- dd->dashPattern << dash << space << dot << space << dot << space;
+ d->dashPattern.reserve(6);
+ d->dashPattern << dash << space << dot << space << dot << space;
break;
default:
break;
}
}
- return dd->dashPattern;
+ return d->dashPattern;
}
/*!
@@ -517,19 +460,18 @@ QVector<qreal> QPen::dashPattern() const
\sa setStyle(), dashPattern(), setCapStyle(), setCosmetic()
*/
-void QPen::setDashPattern(const QVector<qreal> &pattern)
+void QPen::setDashPattern(const QList<qreal> &pattern)
{
if (pattern.isEmpty())
return;
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashPattern = pattern;
+ d->dashPattern = pattern;
d->style = Qt::CustomDashLine;
- if ((dd->dashPattern.size() % 2) == 1) {
+ if ((d->dashPattern.size() % 2) == 1) {
qWarning("QPen::setDashPattern: Pattern not of even length");
- dd->dashPattern << 1;
+ d->dashPattern << 1;
}
}
@@ -541,8 +483,7 @@ void QPen::setDashPattern(const QVector<qreal> &pattern)
*/
qreal QPen::dashOffset() const
{
- QPenData *dd = static_cast<QPenData *>(d);
- return dd->dashOffset;
+ return d->dashOffset;
}
/*!
Sets the dash offset (the starting point on the dash pattern) for this pen
@@ -564,13 +505,12 @@ qreal QPen::dashOffset() const
*/
void QPen::setDashOffset(qreal offset)
{
- if (qFuzzyCompare(offset, static_cast<QPenData *>(d)->dashOffset))
+ if (qFuzzyCompare(offset, d->dashOffset))
return;
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashOffset = offset;
+ d->dashOffset = offset;
if (d->style != Qt::CustomDashLine) {
- dd->dashPattern = dashPattern();
+ d->dashPattern = dashPattern();
d->style = Qt::CustomDashLine;
}
}
@@ -583,8 +523,7 @@ void QPen::setDashOffset(qreal offset)
*/
qreal QPen::miterLimit() const
{
- const QPenData *dd = static_cast<QPenData *>(d);
- return dd->miterLimit;
+ return d->miterLimit;
}
/*!
@@ -606,8 +545,7 @@ qreal QPen::miterLimit() const
void QPen::setMiterLimit(qreal limit)
{
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->miterLimit = limit;
+ d->miterLimit = limit;
}
@@ -653,8 +591,10 @@ qreal QPen::widthF() const
*/
void QPen::setWidth(int width)
{
- if (width < 0)
- qWarning("QPen::setWidth: Setting a pen width with a negative value is not defined");
+ if (width < 0 || width >= (1 << 15)) {
+ qWarning("QPen::setWidth: Setting a pen width that is out of range");
+ return;
+ }
if ((qreal)width == d->width)
return;
detach();
@@ -677,15 +617,14 @@ void QPen::setWidth(int width)
void QPen::setWidthF(qreal width)
{
- if (width < 0.f) {
- qWarning("QPen::setWidthF: Setting a pen width with a negative value is not defined");
+ if (width < 0.f || width >= (1 << 15)) {
+ qWarning("QPen::setWidthF: Setting a pen width that is out of range");
return;
}
if (qAbs(d->width - width) < 0.00000001f)
return;
detach();
d->width = width;
- d->defaultWidth = false;
}
@@ -817,8 +756,7 @@ bool QPen::isSolid() const
bool QPen::isCosmetic() const
{
- QPenData *dd = static_cast<QPenData *>(d);
- return (dd->cosmetic == true) || d->width == 0;
+ return (d->cosmetic == true) || d->width == 0;
}
@@ -832,8 +770,7 @@ bool QPen::isCosmetic() const
void QPen::setCosmetic(bool cosmetic)
{
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->cosmetic = cosmetic;
+ d->cosmetic = cosmetic;
}
@@ -860,20 +797,17 @@ void QPen::setCosmetic(bool cosmetic)
bool QPen::operator==(const QPen &p) const
{
- QPenData *dd = static_cast<QPenData *>(d);
- QPenData *pdd = static_cast<QPenData *>(p.d);
return (p.d == d)
|| (p.d->style == d->style
&& p.d->capStyle == d->capStyle
&& p.d->joinStyle == d->joinStyle
&& p.d->width == d->width
- && pdd->miterLimit == dd->miterLimit
+ && p.d->miterLimit == d->miterLimit
&& (d->style != Qt::CustomDashLine
- || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) &&
- pdd->dashPattern == dd->dashPattern))
+ || (qFuzzyCompare(p.d->dashOffset, d->dashOffset) &&
+ p.d->dashPattern == d->dashPattern))
&& p.d->brush == d->brush
- && pdd->cosmetic == dd->cosmetic
- && pdd->defaultWidth == dd->defaultWidth);
+ && p.d->cosmetic == d->cosmetic);
}
@@ -905,14 +839,13 @@ bool QPen::isDetached()
QDataStream &operator<<(QDataStream &s, const QPen &p)
{
- QPenData *dd = static_cast<QPenData *>(p.d);
if (s.version() < 3) {
s << (quint8)p.style();
} else if (s.version() < QDataStream::Qt_4_3) {
- s << (quint8)(p.style() | p.capStyle() | p.joinStyle());
+ s << (quint8)(uint(p.style()) | uint(p.capStyle()) | uint(p.joinStyle()));
} else {
- s << (quint16)(p.style() | p.capStyle() | p.joinStyle());
- s << (bool)(dd->cosmetic);
+ s << (quint16)(uint(p.style()) | uint(p.capStyle()) | uint(p.joinStyle()));
+ s << (bool)(p.d->cosmetic);
}
if (s.version() < 7) {
@@ -928,7 +861,7 @@ QDataStream &operator<<(QDataStream &s, const QPen &p)
// ensure that we write doubles here instead of streaming the pattern
// directly; otherwise, platforms that redefine qreal might generate
// data that cannot be read on other platforms.
- QVector<qreal> pattern = p.dashPattern();
+ QList<qreal> pattern = p.dashPattern();
s << quint32(pattern.size());
for (int i = 0; i < pattern.size(); ++i)
s << double(pattern.at(i));
@@ -936,7 +869,7 @@ QDataStream &operator<<(QDataStream &s, const QPen &p)
if (s.version() >= 9)
s << double(p.dashOffset());
if (s.version() >= QDataStream::Qt_5_0)
- s << bool(dd->defaultWidth);
+ s << bool(qFuzzyIsNull(p.widthF()));
}
return s;
}
@@ -959,10 +892,10 @@ QDataStream &operator>>(QDataStream &s, QPen &p)
QColor color;
QBrush brush;
double miterLimit = 2;
- QVector<qreal> dashPattern;
+ QList<qreal> dashPattern;
double dashOffset = 0;
bool cosmetic = false;
- bool defaultWidth = false;
+ bool defaultWidth;
if (s.version() < QDataStream::Qt_4_3) {
quint8 style8;
s >> style8;
@@ -998,23 +931,18 @@ QDataStream &operator>>(QDataStream &s, QPen &p)
if (s.version() >= QDataStream::Qt_5_0) {
s >> defaultWidth;
- } else {
- // best we can do for legacy pens
- defaultWidth = qFuzzyIsNull(width);
}
p.detach();
- QPenData *dd = static_cast<QPenData *>(p.d);
- dd->width = width;
- dd->brush = brush;
- dd->style = Qt::PenStyle(style & Qt::MPenStyle);
- dd->capStyle = Qt::PenCapStyle(style & Qt::MPenCapStyle);
- dd->joinStyle = Qt::PenJoinStyle(style & Qt::MPenJoinStyle);
- dd->dashPattern = dashPattern;
- dd->miterLimit = miterLimit;
- dd->dashOffset = dashOffset;
- dd->cosmetic = cosmetic;
- dd->defaultWidth = defaultWidth;
+ p.d->width = width;
+ p.d->brush = brush;
+ p.d->style = Qt::PenStyle(style & Qt::MPenStyle);
+ p.d->capStyle = Qt::PenCapStyle(style & Qt::MPenCapStyle);
+ p.d->joinStyle = Qt::PenJoinStyle(style & Qt::MPenJoinStyle);
+ p.d->dashPattern = dashPattern;
+ p.d->miterLimit = miterLimit;
+ p.d->dashOffset = dashOffset;
+ p.d->cosmetic = cosmetic;
return s;
}
diff --git a/src/gui/painting/qpen.h b/src/gui/painting/qpen.h
index 38282bda39..3367b96c35 100644
--- a/src/gui/painting/qpen.h
+++ b/src/gui/painting/qpen.h
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPEN_H
#define QPEN_H
+#include <QtCore/qshareddata.h>
#include <QtGui/qtguiglobal.h>
#include <QtGui/qcolor.h>
#include <QtGui/qbrush.h>
@@ -57,6 +22,8 @@ Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPen &);
Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPen &);
#endif
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QPenPrivate, Q_GUI_EXPORT)
+
class Q_GUI_EXPORT QPen
{
public:
@@ -70,11 +37,9 @@ public:
~QPen();
QPen &operator=(const QPen &pen) noexcept;
- QPen(QPen &&other) noexcept
- : d(other.d) { other.d = nullptr; }
- QPen &operator=(QPen &&other) noexcept
- { qSwap(d, other.d); return *this; }
- void swap(QPen &other) noexcept { qSwap(d, other.d); }
+ QPen(QPen &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPen)
+ void swap(QPen &other) noexcept { d.swap(other.d); }
Qt::PenStyle style() const;
void setStyle(Qt::PenStyle);
@@ -116,15 +81,19 @@ public:
operator QVariant() const;
bool isDetached();
+
private:
friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPen &);
friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPen &);
+public:
+ using DataPtr = QExplicitlySharedDataPointer<QPenPrivate>;
+
+private:
void detach();
- class QPenPrivate *d;
+ DataPtr d;
public:
- typedef QPenPrivate * DataPtr;
inline DataPtr &data_ptr() { return d; }
};
diff --git a/src/gui/painting/qpen_p.h b/src/gui/painting/qpen_p.h
index 2098be5a53..a939c5e4f6 100644
--- a/src/gui/painting/qpen_p.h
+++ b/src/gui/painting/qpen_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPEN_P_H
#define QPEN_P_H
@@ -51,25 +15,25 @@
// We mean it.
//
-#include <QtCore/qglobal.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
-class QPenPrivate {
+class QPenPrivate : public QSharedData
+{
public:
QPenPrivate(const QBrush &brush, qreal width, Qt::PenStyle, Qt::PenCapStyle,
- Qt::PenJoinStyle _joinStyle, bool defaultWidth = true);
- QAtomicInt ref;
+ Qt::PenJoinStyle _joinStyle);
qreal width;
QBrush brush;
Qt::PenStyle style;
Qt::PenCapStyle capStyle;
Qt::PenJoinStyle joinStyle;
- mutable QVector<qreal> dashPattern;
+ mutable QList<qreal> dashPattern;
qreal dashOffset;
qreal miterLimit;
uint cosmetic : 1;
- uint defaultWidth : 1; // default-constructed width? used for cosmetic pen compatibility
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp
index 42d14bb3b3..4f2f0ae13a 100644
--- a/src/gui/painting/qpixellayout.cpp
+++ b/src/gui/painting/qpixellayout.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qglobal.h>
@@ -43,152 +7,180 @@
#include "qpixellayout_p.h"
#include "qrgba64_p.h"
#include <QtCore/private/qsimd_p.h>
+#include <QtGui/private/qcmyk_p.h>
QT_BEGIN_NAMESPACE
-template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth();
-template<QImage::Format> Q_DECL_CONSTEXPR uint redShift();
-template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth();
-template<QImage::Format> Q_DECL_CONSTEXPR uint greenShift();
-template<QImage::Format> Q_DECL_CONSTEXPR uint blueWidth();
-template<QImage::Format> Q_DECL_CONSTEXPR uint blueShift();
-template<QImage::Format> Q_DECL_CONSTEXPR uint alphaWidth();
-template<QImage::Format> Q_DECL_CONSTEXPR uint alphaShift();
-
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB16>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_BGR888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBX8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
-
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB16>() { return 11; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_BGR888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
+template<QImage::Format> constexpr uint redWidth();
+template<QImage::Format> constexpr uint redShift();
+template<QImage::Format> constexpr uint greenWidth();
+template<QImage::Format> constexpr uint greenShift();
+template<QImage::Format> constexpr uint blueWidth();
+template<QImage::Format> constexpr uint blueShift();
+template<QImage::Format> constexpr uint alphaWidth();
+template<QImage::Format> constexpr uint alphaShift();
+
+template<> constexpr uint redWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_RGB16>() { return 5; }
+template<> constexpr uint redWidth<QImage::Format_RGB444>() { return 4; }
+template<> constexpr uint redWidth<QImage::Format_RGB555>() { return 5; }
+template<> constexpr uint redWidth<QImage::Format_RGB666>() { return 6; }
+template<> constexpr uint redWidth<QImage::Format_RGB888>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_BGR888>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
+template<> constexpr uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
+template<> constexpr uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
+template<> constexpr uint redWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
+template<> constexpr uint redWidth<QImage::Format_RGBX8888>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint redWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+
+template<> constexpr uint redShift<QImage::Format_RGB32>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_ARGB32>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_ARGB32_Premultiplied>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_RGB16>() { return 11; }
+template<> constexpr uint redShift<QImage::Format_RGB444>() { return 8; }
+template<> constexpr uint redShift<QImage::Format_RGB555>() { return 10; }
+template<> constexpr uint redShift<QImage::Format_RGB666>() { return 12; }
+template<> constexpr uint redShift<QImage::Format_RGB888>() { return 16; }
+template<> constexpr uint redShift<QImage::Format_BGR888>() { return 0; }
+template<> constexpr uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
+template<> constexpr uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
+template<> constexpr uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
+template<> constexpr uint redShift<QImage::Format_ARGB6666_Premultiplied>() { return 12; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 24; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 24; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
+template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 24; }
+template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 24; }
+template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
#else
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBX8888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
+template<> constexpr uint redShift<QImage::Format_RGBX8888>() { return 0; }
+template<> constexpr uint redShift<QImage::Format_RGBA8888>() { return 0; }
+template<> constexpr uint redShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
#endif
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB16>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_BGR888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
-
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB16>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_BGR888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
+template<> constexpr uint greenWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_RGB16>() { return 6; }
+template<> constexpr uint greenWidth<QImage::Format_RGB444>() { return 4; }
+template<> constexpr uint greenWidth<QImage::Format_RGB555>() { return 5; }
+template<> constexpr uint greenWidth<QImage::Format_RGB666>() { return 6; }
+template<> constexpr uint greenWidth<QImage::Format_RGB888>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_BGR888>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
+template<> constexpr uint greenWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
+template<> constexpr uint greenWidth<QImage::Format_RGBX8888>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint greenWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+
+template<> constexpr uint greenShift<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_ARGB32_Premultiplied>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_RGB16>() { return 5; }
+template<> constexpr uint greenShift<QImage::Format_RGB444>() { return 4; }
+template<> constexpr uint greenShift<QImage::Format_RGB555>() { return 5; }
+template<> constexpr uint greenShift<QImage::Format_RGB666>() { return 6; }
+template<> constexpr uint greenShift<QImage::Format_RGB888>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_BGR888>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
+template<> constexpr uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
+template<> constexpr uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
+template<> constexpr uint greenShift<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
+template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 16; }
+template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 16; }
+template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
#else
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBX8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_RGBX8888>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint greenShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
#endif
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB16>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_BGR888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
-
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB16>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_BGR888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
+template<> constexpr uint blueWidth<QImage::Format_RGB32>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_RGB16>() { return 5; }
+template<> constexpr uint blueWidth<QImage::Format_RGB444>() { return 4; }
+template<> constexpr uint blueWidth<QImage::Format_RGB555>() { return 5; }
+template<> constexpr uint blueWidth<QImage::Format_RGB666>() { return 6; }
+template<> constexpr uint blueWidth<QImage::Format_RGB888>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_BGR888>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
+template<> constexpr uint blueWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
+template<> constexpr uint blueWidth<QImage::Format_RGBX8888>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint blueWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+
+template<> constexpr uint blueShift<QImage::Format_RGB32>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_ARGB32>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_ARGB32_Premultiplied>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_RGB16>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_RGB444>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_RGB555>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_RGB666>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_RGB888>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_BGR888>() { return 16; }
+template<> constexpr uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
+template<> constexpr uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_ARGB6666_Premultiplied>() { return 0; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
#else
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBX8888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888>() { return 16; }
-template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
+template<> constexpr uint blueShift<QImage::Format_RGBX8888>() { return 16; }
+template<> constexpr uint blueShift<QImage::Format_RGBA8888>() { return 16; }
+template<> constexpr uint blueShift<QImage::Format_RGBA8888_Premultiplied>() { return 16; }
#endif
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB16>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB666>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_BGR888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
-template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
-
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB16>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB666>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_BGR888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB32>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB32>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB32_Premultiplied>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB16>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB444>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB555>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB666>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_RGB888>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_BGR888>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_ARGB6666_Premultiplied>() { return 6; }
+template<> constexpr uint alphaWidth<QImage::Format_RGBX8888>() { return 0; }
+template<> constexpr uint alphaWidth<QImage::Format_RGBA8888>() { return 8; }
+template<> constexpr uint alphaWidth<QImage::Format_RGBA8888_Premultiplied>() { return 8; }
+
+template<> constexpr uint alphaShift<QImage::Format_RGB32>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB32>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB32_Premultiplied>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_RGB16>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGB444>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGB555>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGB666>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGB888>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_BGR888>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_ARGB6666_Premultiplied>() { return 18; }
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 0; }
+template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 0; }
#else
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
-template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_RGBX8888>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_RGBA8888>() { return 24; }
+template<> constexpr uint alphaShift<QImage::Format_RGBA8888_Premultiplied>() { return 24; }
#endif
template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB32>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB32_Premultiplied>() { return QPixelLayout::BPP32; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
@@ -218,20 +210,89 @@ inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index,
reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
}
+template <QPixelLayout::BPP bpp> static
+inline uint QT_FASTCALL fetchPixel(const uchar *, int)
+{
+ Q_UNREACHABLE_RETURN(0);
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (~index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
+{
+ return src[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint16 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint24 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
+{
+ return reinterpret_cast<const uint *>(src)[index];
+}
+
+template <>
+[[maybe_unused]]
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgba64 c = reinterpret_cast<const QRgba64 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+[[maybe_unused]]
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgbaFloat16 c = reinterpret_cast<const QRgbaFloat16 *>(src)[index];
+ return c.toArgb32();
+}
+
+template <>
+[[maybe_unused]]
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
+{
+ // We have to do the conversion in fetch to fit into a 32bit uint
+ QRgbaFloat32 c = reinterpret_cast<const QRgbaFloat32 *>(src)[index];
+ return c.toArgb32();
+}
+
template<QImage::Format Format>
-static Q_ALWAYS_INLINE uint convertPixelToRGB32(uint s)
+static inline uint convertPixelToRGB32(uint s)
{
- Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1);
- Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1);
- Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1);
+ constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
+ constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
+ constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
- Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>();
- Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>();
- Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>();
+ constexpr uchar redLeftShift = 8 - redWidth<Format>();
+ constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
+ constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
- Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8;
- Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8;
- Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8;
+ constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
+ constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
+ constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
uint red = (s >> redShift<Format>()) & redMask;
uint green = (s >> greenShift<Format>()) & greenMask;
@@ -244,7 +305,7 @@ static Q_ALWAYS_INLINE uint convertPixelToRGB32(uint s)
}
template<QImage::Format Format>
-static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGB32<Format>(buffer[i]);
@@ -256,7 +317,7 @@ extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*s
template<QImage::Format Format>
static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
@@ -269,19 +330,19 @@ static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, i
}
#endif
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB32<Format>(qFetchPixel<BPP>(src, index + i));
+ buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
return buffer;
}
template<QImage::Format Format>
-static Q_ALWAYS_INLINE QRgba64 convertPixelToRGB64(uint s)
+static inline QRgba64 convertPixelToRGB64(uint s)
{
return QRgba64::fromArgb32(convertPixelToRGB32<Format>(s));
}
template<QImage::Format Format>
static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGB64<Format>(src[i]);
@@ -290,32 +351,47 @@ static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *sr
template<QImage::Format Format>
static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGB64<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static Q_ALWAYS_INLINE QRgbaFloat32 convertPixelToRGB32F(uint s)
+{
+ return QRgbaFloat32::fromArgb32(convertPixelToRGB32<Format>(s));
+}
+
+template<QImage::Format Format>
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBToRGB32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB64<Format>(qFetchPixel<bitsPerPixel<Format>()>(src, index + i));
+ buffer[i] = convertPixelToRGB32F<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
return buffer;
}
template<QImage::Format Format>
-static Q_ALWAYS_INLINE uint convertPixelToARGB32PM(uint s)
+static inline uint convertPixelToARGB32PM(uint s)
{
- Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
- Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1);
- Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1);
- Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1);
+ constexpr uint alphaMask = ((1 << alphaWidth<Format>()) - 1);
+ constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
+ constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
+ constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
- Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth<Format>();
- Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>();
- Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>();
- Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>();
+ constexpr uchar alphaLeftShift = 8 - alphaWidth<Format>();
+ constexpr uchar redLeftShift = 8 - redWidth<Format>();
+ constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
+ constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
- Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
- Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8;
- Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8;
- Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8;
+ constexpr uchar alphaRightShift = 2 * alphaWidth<Format>() - 8;
+ constexpr uchar redRightShift = 2 * redWidth<Format>() - 8;
+ constexpr uchar greenRightShift = 2 * greenWidth<Format>() - 8;
+ constexpr uchar blueRightShift = 2 * blueWidth<Format>() - 8;
- Q_CONSTEXPR bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
+ constexpr bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
(alphaWidth<Format>() != greenWidth<Format>()) ||
(alphaWidth<Format>() != blueWidth<Format>());
@@ -339,7 +415,7 @@ static Q_ALWAYS_INLINE uint convertPixelToARGB32PM(uint s)
}
template<QImage::Format Format>
-static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]);
@@ -347,7 +423,7 @@ static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const Q
template<QImage::Format Format>
static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
@@ -360,19 +436,19 @@ static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *
}
#endif
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToARGB32PM<Format>(qFetchPixel<BPP>(src, index + i));
+ buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
return buffer;
}
template<QImage::Format Format>
-static Q_ALWAYS_INLINE QRgba64 convertPixelToRGBA64PM(uint s)
+static inline QRgba64 convertPixelToRGBA64PM(uint s)
{
return QRgba64::fromArgb32(convertPixelToARGB32PM<Format>(s));
}
template<QImage::Format Format>
static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = convertPixelToRGB64<Format>(src[i]);
@@ -381,31 +457,57 @@ static const QRgba64 *QT_FASTCALL convertARGBPMToRGBA64PM(QRgba64 *buffer, const
template<QImage::Format Format>
static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGBA64PM<Format>(qFetchPixel<bpp>(src, index + i));
+ buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static Q_ALWAYS_INLINE QRgbaFloat32 convertPixelToRGBA32F(uint s)
+{
+ return QRgbaFloat32::fromArgb32(convertPixelToARGB32PM<Format>(s));
+}
+
+template<QImage::Format Format>
+static const QRgbaFloat32 *QT_FASTCALL fetchARGBPMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static const QRgbaFloat32 *QT_FASTCALL fetchARGBToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGBA32F<Format>(fetchPixel<bpp>(src, index + i)).premultiplied();
return buffer;
}
template<QImage::Format Format, bool fromRGB>
static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *dither)
+ const QList<QRgb> *, QDitherInfo *dither)
{
- Q_CONSTEXPR uchar rWidth = redWidth<Format>();
- Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
- Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
+ constexpr uchar rWidth = redWidth<Format>();
+ constexpr uchar gWidth = greenWidth<Format>();
+ constexpr uchar bWidth = blueWidth<Format>();
constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
// RGB32 -> RGB888 is not a precision loss.
if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) {
- Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1;
- Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1;
- Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1;
- Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>();
- Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>();
- Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>();
+ constexpr uint rMask = (1 << redWidth<Format>()) - 1;
+ constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
+ constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
+ constexpr uchar rRightShift = 24 - redWidth<Format>();
+ constexpr uchar gRightShift = 16 - greenWidth<Format>();
+ constexpr uchar bRightShift = 8 - blueWidth<Format>();
for (int i = 0; i < count; ++i) {
const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
@@ -443,21 +545,21 @@ static void QT_FASTCALL storeRGBFromARGB32PM(uchar *dest, const uint *src, int i
template<QImage::Format Format, bool fromRGB>
static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *dither)
+ const QList<QRgb> *, QDitherInfo *dither)
{
constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
if (!dither) {
- Q_CONSTEXPR uint aMask = (1 << alphaWidth<Format>()) - 1;
- Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1;
- Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1;
- Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1;
+ constexpr uint aMask = (1 << alphaWidth<Format>()) - 1;
+ constexpr uint rMask = (1 << redWidth<Format>()) - 1;
+ constexpr uint gMask = (1 << greenWidth<Format>()) - 1;
+ constexpr uint bMask = (1 << blueWidth<Format>()) - 1;
- Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth<Format>();
- Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>();
- Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>();
- Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>();
+ constexpr uchar aRightShift = 32 - alphaWidth<Format>();
+ constexpr uchar rRightShift = 24 - redWidth<Format>();
+ constexpr uchar gRightShift = 16 - greenWidth<Format>();
+ constexpr uchar bRightShift = 8 - blueWidth<Format>();
- Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>();
+ constexpr uint aOpaque = aMask << alphaShift<Format>();
for (int i = 0; i < count; ++i) {
const uint c = src[i];
const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>());
@@ -467,10 +569,10 @@ static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, in
storePixel<BPP>(dest, index + i, a | r | g | b);
};
} else {
- Q_CONSTEXPR uchar aWidth = alphaWidth<Format>();
- Q_CONSTEXPR uchar rWidth = redWidth<Format>();
- Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
- Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
+ constexpr uchar aWidth = alphaWidth<Format>();
+ constexpr uchar rWidth = redWidth<Format>();
+ constexpr uchar gWidth = greenWidth<Format>();
+ constexpr uchar bWidth = blueWidth<Format>();
const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
for (int i = 0; i < count; ++i) {
@@ -503,24 +605,22 @@ static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, in
template<QImage::Format Format>
static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
{
- Q_CONSTEXPR uchar aWidth = alphaWidth<Format>();
- Q_CONSTEXPR uchar aShift = alphaShift<Format>();
- Q_CONSTEXPR uchar rWidth = redWidth<Format>();
- Q_CONSTEXPR uchar rShift = redShift<Format>();
- Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
- Q_CONSTEXPR uchar gShift = greenShift<Format>();
- Q_CONSTEXPR uchar bWidth = blueWidth<Format>();
- Q_CONSTEXPR uchar bShift = blueShift<Format>();
-#ifdef Q_COMPILER_CONSTEXPR
+ constexpr uchar aWidth = alphaWidth<Format>();
+ constexpr uchar aShift = alphaShift<Format>();
+ constexpr uchar rWidth = redWidth<Format>();
+ constexpr uchar rShift = redShift<Format>();
+ constexpr uchar gWidth = greenWidth<Format>();
+ constexpr uchar gShift = greenShift<Format>();
+ constexpr uchar bWidth = blueWidth<Format>();
+ constexpr uchar bShift = blueShift<Format>();
static_assert(rWidth == bWidth);
-#endif
- Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1;
- Q_CONSTEXPR uint alphaGreenMask = (((1 << aWidth) - 1) << aShift)
+ constexpr uint redBlueMask = (1 << rWidth) - 1;
+ constexpr uint alphaGreenMask = (((1 << aWidth) - 1) << aShift)
| (((1 << gWidth) - 1) << gShift);
constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i) {
- const uint c = qFetchPixel<bpp>(src, i);
+ const uint c = fetchPixel<bpp>(src, i);
const uint r = (c >> rShift) & redBlueMask;
const uint b = (c >> bShift) & redBlueMask;
const uint t = (c & alphaGreenMask)
@@ -570,7 +670,49 @@ static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
}
-template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
+static void QT_FASTCALL rbSwap_4x16(uchar *d, const uchar *s, int count)
+{
+ const ushort *src = reinterpret_cast<const ushort *>(s);
+ ushort *dest = reinterpret_cast<ushort *>(d);
+ if (src != dest) {
+ for (int i = 0; i < count; ++i) {
+ dest[i * 4 + 0] = src[i * 4 + 2];
+ dest[i * 4 + 1] = src[i * 4 + 1];
+ dest[i * 4 + 2] = src[i * 4 + 0];
+ dest[i * 4 + 3] = src[i * 4 + 3];
+ }
+ } else {
+ for (int i = 0; i < count; ++i) {
+ const ushort r = src[i * 4 + 0];
+ const ushort b = src[i * 4 + 2];
+ dest[i * 4 + 0] = b;
+ dest[i * 4 + 2] = r;
+ }
+ }
+}
+
+static void QT_FASTCALL rbSwap_4x32(uchar *d, const uchar *s, int count)
+{
+ const uint *src = reinterpret_cast<const uint *>(s);
+ uint *dest = reinterpret_cast<uint *>(d);
+ if (src != dest) {
+ for (int i = 0; i < count; ++i) {
+ dest[i * 4 + 0] = src[i * 4 + 2];
+ dest[i * 4 + 1] = src[i * 4 + 1];
+ dest[i * 4 + 2] = src[i * 4 + 0];
+ dest[i * 4 + 3] = src[i * 4 + 3];
+ }
+ } else {
+ for (int i = 0; i < count; ++i) {
+ const uint r = src[i * 4 + 0];
+ const uint b = src[i * 4 + 2];
+ dest[i * 4 + 0] = b;
+ dest[i * 4 + 2] = r;
+ }
+ }
+}
+
+template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutRGB()
{
return QPixelLayout{
false,
@@ -586,7 +728,7 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe
};
}
-template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM()
+template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutARGBPM()
{
return QPixelLayout{
true,
@@ -602,7 +744,7 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe
};
}
-static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QVector<QRgb> *clut)
+static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QList<QRgb> *clut)
{
for (int i = 0; i < count; ++i)
buffer[i] = qPremultiply(clut->at(buffer[i]));
@@ -610,10 +752,10 @@ static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const
template<QPixelLayout::BPP BPP>
static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
+ const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
- const uint s = qFetchPixel<BPP>(src, index + i);
+ const uint s = fetchPixel<BPP>(src, index + i);
buffer[i] = qPremultiply(clut->at(s));
}
return buffer;
@@ -621,113 +763,128 @@ static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar
template<QPixelLayout::BPP BPP>
static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
+ const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
- const uint s = qFetchPixel<BPP>(src, index + i);
+ const uint s = fetchPixel<BPP>(src, index + i);
buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
}
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
+template<QPixelLayout::BPP BPP>
+static const QRgbaFloat32 *QT_FASTCALL fetchIndexedToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i) {
+ const uint s = fetchPixel<BPP>(src, index + i);
+ buffer[i] = QRgbaFloat32::fromArgb32(clut->at(s)).premultiplied();
+ }
+ return buffer;
+}
+
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertIndexedTo(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied();
+ buffer[i] = QRgba::fromArgb32(clut->at(src[i])).premultiplied();
return buffer;
}
-static void QT_FASTCALL convertPassThrough(uint *, int, const QVector<QRgb> *)
+static void QT_FASTCALL convertPassThrough(uint *, int, const QList<QRgb> *)
{
}
static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return reinterpret_cast<const uint *>(src) + index;
}
static const QRgba64 *QT_FASTCALL fetchPassThrough64(QRgba64 *, const uchar *src, int index, int,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return reinterpret_cast<const QRgba64 *>(src) + index;
}
static void QT_FASTCALL storePassThrough(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
if (d != src)
memcpy(d, src, count * sizeof(uint));
}
-static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
qt_convertARGB32ToARGB32PM(buffer, buffer, count);
}
static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return qt_convertARGB32ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
}
-static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i)
buffer[i] = RGBA2ARGB(buffer[i]);
}
static const uint *QT_FASTCALL fetchRGBA8888PMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
const uint *s = reinterpret_cast<const uint *>(src) + index;
UNALIASED_CONVERSION_LOOP(buffer, s, count, RGBA2ARGB);
return buffer;
}
-static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
}
static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return qt_convertRGBA8888ToARGB32PM(buffer, reinterpret_cast<const uint *>(src) + index, count);
}
-static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertAlpha8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qRgba(0, 0, 0, buffer[i]);
}
static const uint *QT_FASTCALL fetchAlpha8ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qRgba(0, 0, 0, src[index + i]);
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertAlpha8To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]);
+ buffer[i] = QRgba::fromRgba(0, 0, 0, src[i]);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchAlpha8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchAlpha8To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(0, 0, 0, src[index + i]);
+ buffer[i] = QRgba::fromRgba(0, 0, 0, src[index + i]);
return buffer;
}
-static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i) {
const uint s = buffer[i];
@@ -736,7 +893,7 @@ static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const
}
static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = src[index + i];
@@ -745,34 +902,35 @@ static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertGrayscale8To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255);
+ buffer[i] = QRgba::fromRgba(src[i], src[i], src[i], 255);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchGrayscale8ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchGrayscale8To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i) {
const uint s = src[index + i];
- buffer[i] = QRgba64::fromRgba(s, s, s, 255);
+ buffer[i] = QRgba::fromRgba(s, s, s, 255);
}
return buffer;
}
-static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i) {
const uint x = qt_div_257(buffer[i]);
buffer[i] = qRgb(x, x, x);
}
}
-
static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
for (int i = 0; i < count; ++i) {
@@ -782,34 +940,35 @@ static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar
return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertGrayscale16To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
- const unsigned short *s = reinterpret_cast<const unsigned short *>(src);
for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
+ buffer[i] = QRgba::fromRgba64(src[i], src[i], src[i], 65535);
return buffer;
}
-static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+template<typename QRgba>
+static const QRgba *QT_FASTCALL fetchGrayscale16To(QRgba *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
{
const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
for (int i = 0; i < count; ++i) {
- buffer[i] = QRgba64::fromRgba64(s[i], s[i], s[i], 65535);
+ buffer[i] = QRgba::fromRgba64(s[i], s[i], s[i], 65535);
}
return buffer;
}
static void QT_FASTCALL storeARGB32FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return qUnpremultiply(c); });
}
static void QT_FASTCALL storeRGBA8888PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
@@ -970,7 +1129,7 @@ static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *
#endif
static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
@@ -984,13 +1143,13 @@ static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uin
}
static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertRGB32ToRGB64(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
@@ -998,13 +1157,13 @@ static const QRgba64 *QT_FASTCALL convertARGB32ToRGBA64PM(QRgba64 *buffer, const
}
static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertARGB32ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
@@ -1018,22 +1177,33 @@ static const QRgba64 *QT_FASTCALL convertARGB32PMToRGBA64PM(QRgba64 *buffer, con
}
static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+#ifdef __SSE2__
+ for (int i = 0; i < count; ++i) {
+ const auto a = s[i].alpha();
+ __m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
+ __m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
+ vs = multiplyAlpha65535(vs, va);
+ _mm_storel_epi64((__m128i *)(buffer + i), vs);
+ buffer[i].setAlpha(a);
+ }
+#else
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
+#endif
return buffer;
}
static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
@@ -1041,13 +1211,13 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, con
}
static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertRGBA8888ToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
@@ -1061,34 +1231,34 @@ static const QRgba64 *QT_FASTCALL convertRGBA8888PMToRGBA64PM(QRgba64 *buffer, c
}
static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertRGBA8888PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
static void QT_FASTCALL storeRGBA8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(qUnpremultiply(c)); });
}
static void QT_FASTCALL storeRGBXFromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); });
}
static void QT_FASTCALL storeRGBXFromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | qUnpremultiply(c)); });
}
template<QtPixelOrder PixelOrder>
-static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
+static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
{
for (int i = 0; i < count; ++i)
buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
@@ -1096,7 +1266,7 @@ static void QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, int count, cons
template<QtPixelOrder PixelOrder>
static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
- const QVector<QRgb> *, QDitherInfo *dither)
+ const QList<QRgb> *, QDitherInfo *dither)
{
const uint *src = reinterpret_cast<const uint *>(s) + index;
if (!dither) {
@@ -1167,7 +1337,7 @@ static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint
template<QtPixelOrder PixelOrder>
static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
#ifdef __SSE2__
qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
@@ -1180,14 +1350,52 @@ static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, co
template<QtPixelOrder PixelOrder>
static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
return convertA2RGB30PMToRGBA64PM<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
}
+template<enum QtPixelOrder> inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP(uint rgb);
+
+template<>
+inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderBGR>(uint rgb)
+{
+ float alpha = (rgb >> 30) * (1.f/3.f);
+ float blue = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
+ float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
+ float red = (rgb & 0x3ff) * (1.f/1023.f);
+ return QRgbaFloat32{ red, green, blue, alpha };
+}
+
+template<>
+inline QRgbaFloat32 qConvertA2rgb30ToRgbaFP<PixelOrderRGB>(uint rgb)
+{
+ float alpha = (rgb >> 30) * (1.f/3.f);
+ float red = ((rgb >> 20) & 0x3ff) * (1.f/1023.f);
+ float green = ((rgb >> 10) & 0x3ff) * (1.f/1023.f);
+ float blue = (rgb & 0x3ff) * (1.f/1023.f);
+ return QRgbaFloat32{ red, green, blue, alpha };
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgbaFloat32 *QT_FASTCALL convertA2RGB30PMToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertA2rgb30ToRgbaFP<PixelOrder>(src[i]);
+ return buffer;
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgbaFloat32 *QT_FASTCALL fetchRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ return convertA2RGB30PMToRGBA32F<PixelOrder>(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
+}
+
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
@@ -1195,7 +1403,7 @@ static void QT_FASTCALL storeA2RGB30PMFromARGB32PM(uchar *dest, const uint *src,
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
@@ -1203,7 +1411,7 @@ static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int in
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = reinterpret_cast<uint *>(dest) + index;
UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
@@ -1256,28 +1464,28 @@ template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int
static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
dest[index + i] = qAlpha(src[i]);
}
static void QT_FASTCALL storeGrayscale8FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
dest[index + i] = qGray(src[i]);
}
static void QT_FASTCALL storeGrayscale8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
dest[index + i] = qGray(qUnpremultiply(src[i]));
}
static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
for (int i = 0; i < count; ++i)
@@ -1285,7 +1493,7 @@ static void QT_FASTCALL storeGrayscale16FromRGB32(uchar *dest, const uint *src,
}
static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
for (int i = 0; i < count; ++i)
@@ -1293,7 +1501,7 @@ static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *sr
}
static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
for (int i = 0; i < count; ++i)
@@ -1302,15 +1510,15 @@ static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src,
}
static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
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,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
for (int i = 0; i < count; ++i)
@@ -1318,30 +1526,214 @@ static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *buffer, const uchar *
return buffer;
}
+template<bool Mask>
static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ 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]);
+}
+
+static const uint *QT_FASTCALL fetchRGB16FToRGB32(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].toArgb32();
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGB16FFromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgbaFloat16::fromArgb32(src[i]);
+}
+
+static const uint *QT_FASTCALL fetchRGBA16FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied().toArgb32();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA16FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat16 c = s[i].premultiplied();
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGBA16FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgbaFloat16::fromArgb32(src[i]).unpremultiplied();
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA16FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat16 c = s[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static const uint *QT_FASTCALL fetchRGB32FToRGB32(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].toArgb32();
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGB32FFromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgbaFloat32::fromArgb32(src[i]);
+}
+
+static const uint *QT_FASTCALL fetchRGBA32FToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied().toArgb32();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA32FToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat32 c = s[i].premultiplied();
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGBA32FFromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QRgbaFloat32::fromArgb32(src[i]).unpremultiplied();
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgbaFloat32 c = s[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
+ }
+ return buffer;
+}
+
+inline const uint *qt_convertCMYK8888ToARGB32PM(uint *buffer, const uint *src, int count)
+{
+ UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) {
+ const QColor color = QCmyk32::fromCmyk32(s).toColor();
+ return color.rgba();
+ });
+ return buffer;
+}
+
+static void QT_FASTCALL convertCMYK8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
+{
+ qt_convertCMYK8888ToARGB32PM(buffer, buffer, count);
+}
+
+static const QRgba64 *QT_FASTCALL convertCMYK8888ToToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(src[i]).toColor().rgba64();
+ return buffer;
+}
+
+static const uint *QT_FASTCALL fetchCMYK8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchCMYK8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba64();
+ return buffer;
+}
+
+static void QT_FASTCALL storeCMYK8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ QColor c = qUnpremultiply(src[i]);
+ d[i] = QCmyk32::fromColor(c).toUint();
+ }
+}
+
+static void QT_FASTCALL storeCMYK8888FromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ QColor c = src[i];
+ d[i] = QCmyk32::fromColor(c).toUint();
+ }
}
// Note:
// convertToArgb32() assumes that no color channel is less than 4 bits.
// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
-QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
+QPixelLayout qPixelLayouts[] = {
{ false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
{ false, false, QPixelLayout::BPP1MSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
nullptr, nullptr }, // Format_Mono
{ false, false, QPixelLayout::BPP1LSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
nullptr, nullptr }, // Format_MonoLSB
{ false, false, QPixelLayout::BPP8, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
nullptr, nullptr }, // Format_Indexed8
// Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
@@ -1400,33 +1792,61 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
storeRGB30FromRGB32<PixelOrderRGB>
}, // Format_A2RGB30_Premultiplied
{ true, true, QPixelLayout::BPP8, nullptr,
- convertAlpha8ToRGB32, convertAlpha8ToRGB64,
- fetchAlpha8ToRGB32, fetchAlpha8ToRGB64,
+ convertAlpha8ToRGB32, convertAlpha8To<QRgba64>,
+ fetchAlpha8ToRGB32, fetchAlpha8To<QRgba64>,
storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
{ false, false, QPixelLayout::BPP8, nullptr,
- convertGrayscale8ToRGB32, convertGrayscale8ToRGB64,
- fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64,
+ convertGrayscale8ToRGB32, convertGrayscale8To<QRgba64>,
+ fetchGrayscale8ToRGB32, fetchGrayscale8To<QRgba64>,
storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
- { false, false, QPixelLayout::BPP64, nullptr,
+ { false, false, QPixelLayout::BPP64, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64
- { true, false, QPixelLayout::BPP64, nullptr,
+ storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
+ { true, false, QPixelLayout::BPP64, rbSwap_4x16,
convertARGB32ToARGB32PM, nullptr,
fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
- storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64
- { true, true, QPixelLayout::BPP64, nullptr,
+ storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
+ { true, true, QPixelLayout::BPP64, rbSwap_4x16,
convertPassThrough, nullptr,
fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
+ storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
{ false, false, QPixelLayout::BPP16, nullptr,
- convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
- fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
+ convertGrayscale16ToRGB32, convertGrayscale16To<QRgba64>,
+ fetchGrayscale16ToRGB32, fetchGrayscale16To<QRgba64>,
storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
pixelLayoutRGB<QImage::Format_BGR888>(),
+ { false, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
+ storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBX16FPx4
+ { true, false, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertARGB32ToARGB32PM, nullptr,
+ fetchRGBA16FToARGB32PM, fetchRGBA16FToRGBA64PM,
+ storeRGBA16FFromARGB32PM, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4
+ { true, true, QPixelLayout::BPP16FPx4, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB16FToRGB32, fetchRGBA16FPMToRGBA64PM,
+ storeRGB16FFromRGB32, storeRGB16FFromRGB32 }, // Format_RGBA16FPx4_Premultiplied
+ { false, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertPassThrough, nullptr,
+ fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
+ storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBX32FPx4
+ { true, false, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertARGB32ToARGB32PM, nullptr,
+ fetchRGBA32FToARGB32PM, fetchRGBA32FToRGBA64PM,
+ storeRGBA32FFromARGB32PM, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4
+ { true, true, QPixelLayout::BPP32FPx4, rbSwap_4x32,
+ convertPassThrough, nullptr,
+ fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
+ storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied
+ { false, false, QPixelLayout::BPP32, nullptr,
+ convertCMYK8888ToARGB32PM, convertCMYK8888ToToRGBA64PM,
+ fetchCMYK8888ToARGB32PM, fetchCMYK8888ToRGBA64PM,
+ storeCMYK8888FromARGB32PM, storeCMYK8888FromRGB32 }, // Format_CMYK8888
};
-static_assert(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
+static_assert(std::size(qPixelLayouts) == QImage::NImageFormats);
static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
{
@@ -1437,7 +1857,7 @@ static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int len
template<QImage::Format format>
static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither)
+ const QList<QRgb> *clut, QDitherInfo *dither)
{
uint buffer[BufferSize];
convertFromRgb64(buffer, src, count);
@@ -1445,7 +1865,7 @@ static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src
}
static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i)
@@ -1453,7 +1873,7 @@ static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i)
@@ -1462,7 +1882,7 @@ static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *sr
template<QtPixelOrder PixelOrder>
static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
#ifdef __SSE2__
@@ -1474,7 +1894,7 @@ static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
for (int i = 0; i < count; ++i) {
@@ -1484,7 +1904,7 @@ static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
for (int i = 0; i < count; ++i)
@@ -1492,7 +1912,7 @@ static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
if (d != src)
@@ -1500,7 +1920,7 @@ static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *sr
}
static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+ const QList<QRgb> *, QDitherInfo *)
{
quint16 *d = reinterpret_cast<quint16*>(dest) + index;
for (int i = 0; i < count; ++i) {
@@ -1509,7 +1929,67 @@ static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src,
}
}
-ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
+static void QT_FASTCALL storeRGBX16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
+ d[i].setAlpha(1.0);
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF16(src[i]).unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA16FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF16(src[i]);
+}
+
+static void QT_FASTCALL storeRGBX32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
+ d[i].setAlpha(1.0);
+ }
+}
+
+static void QT_FASTCALL storeRGBA32FFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF32(src[i]).unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgbaF32(src[i]);
+}
+
+static void QT_FASTCALL storeCMYKFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QCmyk32::fromColor(QColor(src[i])).toUint();
+}
+
+ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[] = {
nullptr,
nullptr,
nullptr,
@@ -1540,6 +2020,417 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
storeRGBA64PMFromRGBA64PM,
storeGray16FromRGBA64PM,
storeGenericFromRGBA64PM<QImage::Format_BGR888>,
+ storeRGBX16FFromRGBA64PM,
+ storeRGBA16FFromRGBA64PM,
+ storeRGBA16FPMFromRGBA64PM,
+ storeRGBX32FFromRGBA64PM,
+ storeRGBA32FFromRGBA64PM,
+ storeRGBA32FPMFromRGBA64PM,
+ storeCMYKFromRGBA64PM,
};
+static_assert(std::size(qStoreFromRGBA64PM) == QImage::NImageFormats);
+
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL convertToRgbaF32(QRgbaFloat32 *dest, const uint *src, int length)
+{
+ for (int i = 0; i < length; ++i)
+ dest[i] = QRgbaFloat32::fromArgb32(src[i]);
+}
+
+template<QImage::Format format>
+static const QRgbaFloat32 * QT_FASTCALL convertGenericToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *)
+{
+ uint buffer32[BufferSize];
+ memcpy(buffer32, src, count * sizeof(uint));
+ qPixelLayouts[format].convertToARGB32PM(buffer32, count, clut);
+ convertToRgbaF32(buffer, buffer32, count);
+ return buffer;
+}
+
+static const QRgbaFloat32 * QT_FASTCALL convertARGB32ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(src[i]).premultiplied();
+ return buffer;
+}
+
+static const QRgbaFloat32 * QT_FASTCALL convertRGBA8888ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
+ return buffer;
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgbaFloat32 * QT_FASTCALL convertRGB30ToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i) {
+ QRgba64 s = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
+ buffer[i] = QRgbaFloat32::fromRgba64(s.red(), s.green(), s.blue(), s.alpha());
+ }
+ return buffer;
+}
+
+static const QRgbaFloat32 * QT_FASTCALL convertCMYKToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(src[i]).toColor().rgba());
+
+ return buffer;
+}
+
+ConvertToFPFunc qConvertToRGBA32F[] = {
+ nullptr,
+ convertIndexedTo<QRgbaFloat32>,
+ convertIndexedTo<QRgbaFloat32>,
+ convertIndexedTo<QRgbaFloat32>,
+ convertGenericToRGBA32F<QImage::Format_RGB32>,
+ convertARGB32ToRGBA32F,
+ convertGenericToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB16>,
+ convertGenericToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB666>,
+ convertGenericToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB555>,
+ convertGenericToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGB888>,
+ convertGenericToRGBA32F<QImage::Format_RGB444>,
+ convertGenericToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ convertGenericToRGBA32F<QImage::Format_RGBX8888>,
+ convertRGBA8888ToRGBA32F,
+ convertGenericToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ convertRGB30ToRGBA32F<PixelOrderBGR>,
+ convertRGB30ToRGBA32F<PixelOrderBGR>,
+ convertRGB30ToRGBA32F<PixelOrderRGB>,
+ convertRGB30ToRGBA32F<PixelOrderRGB>,
+ convertAlpha8To<QRgbaFloat32>,
+ convertGrayscale8To<QRgbaFloat32>,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertGrayscale16To<QRgbaFloat32>,
+ convertGenericToRGBA32F<QImage::Format_BGR888>,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ convertCMYKToRGBA32F,
+};
+
+static_assert(std::size(qConvertToRGBA32F) == QImage::NImageFormats);
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBX64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba64 c = s[i];
+ buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), 65535);
+ }
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb64ToRgbaF32(s[i]).premultiplied();
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA64PMToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb64ToRgbaF32(s[i]);
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ auto c = s[i].premultiplied();
+ buffer[i] = QRgbaFloat32 { c.r, c.g, c.b, c.a};
+ }
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA16F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat16 *s = reinterpret_cast<const QRgbaFloat16 *>(src) + index;
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)s, count * 4);
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32FToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = s[i].premultiplied();
+ return buffer;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32F(QRgbaFloat32 *, const uchar *src, int index, int,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const QRgbaFloat32 *s = reinterpret_cast<const QRgbaFloat32 *>(src) + index;
+ return s;
+}
+
+static const QRgbaFloat32 *QT_FASTCALL fetchCMYKToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(s[i]).toColor().rgba());
+
+ return buffer;
+}
+
+FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = {
+ nullptr,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP1LSB>,
+ fetchIndexedToRGBA32F<QPixelLayout::BPP8>,
+ fetchRGBToRGB32F<QImage::Format_RGB32>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB32>,
+ fetchARGBPMToRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB16>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB666>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB555>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGB888>,
+ fetchRGBToRGB32F<QImage::Format_RGB444>,
+ fetchARGBToRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ fetchRGBToRGB32F<QImage::Format_RGBX8888>,
+ fetchARGBToRGBA32F<QImage::Format_RGBA8888>,
+ fetchARGBPMToRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ fetchRGB30ToRGBA32F<PixelOrderBGR>,
+ fetchRGB30ToRGBA32F<PixelOrderBGR>,
+ fetchRGB30ToRGBA32F<PixelOrderRGB>,
+ fetchRGB30ToRGBA32F<PixelOrderRGB>,
+ fetchAlpha8To<QRgbaFloat32>,
+ fetchGrayscale8To<QRgbaFloat32>,
+ fetchRGBX64ToRGBA32F,
+ fetchRGBA64ToRGBA32F,
+ fetchRGBA64PMToRGBA32F,
+ fetchGrayscale16To<QRgbaFloat32>,
+ fetchRGBToRGB32F<QImage::Format_BGR888>,
+ fetchRGBA16F,
+ fetchRGBA16FToRGBA32F,
+ fetchRGBA16F,
+ fetchRGBA32F,
+ fetchRGBA32FToRGBA32F,
+ fetchRGBA32F,
+ fetchCMYKToRGBA32F,
+};
+
+static_assert(std::size(qFetchToRGBA32F) == QImage::NImageFormats);
+
+static void QT_FASTCALL convertFromRgba32f(uint *dest, const QRgbaFloat32 *src, int length)
+{
+ for (int i = 0; i < length; ++i)
+ dest[i] = src[i].toArgb32();
+}
+
+template<QImage::Format format>
+static void QT_FASTCALL storeGenericFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither)
+{
+ uint buffer[BufferSize];
+ convertFromRgba32f(buffer, src, count);
+ qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
+}
+
+static void QT_FASTCALL storeARGB32FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i].unpremultiplied().toArgb32();
+}
+
+static void QT_FASTCALL storeRGBA8888FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = ARGB2RGBA(src[i].unpremultiplied().toArgb32());
+}
+
+template<QtPixelOrder PixelOrder>
+static void QT_FASTCALL storeRGB30FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i];
+ d[i] = qConvertRgb64ToRgb30<PixelOrder>(QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16()));
+ }
+}
+
+static void QT_FASTCALL storeRGBX64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i].unpremultiplied();
+ d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), 65535);
+ }
+}
+
+static void QT_FASTCALL storeRGBA64FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ const auto s = src[i].unpremultiplied();
+ d[i] = QRgba64::fromRgba64(s.red16(), s.green16(), s.blue16(), s.alpha16());
+ }
+}
+
+static void QT_FASTCALL storeRGBA64PMFromRGBA32F(uchar *dest, const QRgbaFloat32 *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::fromRgba64(src[i].red16(), src[i].green16(), src[i].blue16(), src[i].alpha16());
+}
+
+static void QT_FASTCALL storeGray16FromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint16 *d = reinterpret_cast<quint16 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = qGray(s.red16(), s.green16(), s.blue16());
+ }
+}
+
+static void QT_FASTCALL storeRGBX16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(1.0f) };
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ d[i] = QRgbaFloat16{ qfloat16(s.r), qfloat16(s.g), qfloat16(s.b), qfloat16(s.a) };
+ }
+}
+
+static void QT_FASTCALL storeRGBA16FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat16 *d = reinterpret_cast<QRgbaFloat16 *>(dest) + index;
+ qFloatToFloat16((qfloat16 *)d, (const float *)src, count * 4);
+}
+
+static void QT_FASTCALL storeRGBX32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ auto s = src[i].unpremultiplied();
+ s.a = 1.0f;
+ d[i] = s;
+ }
+}
+
+static void QT_FASTCALL storeRGBA32FFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i].unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgbaFloat32 *d = reinterpret_cast<QRgbaFloat32 *>(dest) + index;
+ if (d != src) {
+ for (int i = 0; i < count; ++i)
+ d[i] = src[i];
+ }
+}
+
+static void QT_FASTCALL storeCMYKFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ // Yikes, this really needs enablers in QColor and friends
+ d[i] = QCmyk32::fromColor(QColor(src[i].toArgb32())).toUint();
+ }
+}
+
+ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = {
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ storeGenericFromRGBA32F<QImage::Format_RGB32>,
+ storeARGB32FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_ARGB32_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB16>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB8565_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB666>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB6666_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB555>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB8555_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGB888>,
+ storeGenericFromRGBA32F<QImage::Format_RGB444>,
+ storeGenericFromRGBA32F<QImage::Format_ARGB4444_Premultiplied>,
+ storeGenericFromRGBA32F<QImage::Format_RGBX8888>,
+ storeRGBA8888FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_RGBA8888_Premultiplied>,
+ storeRGB30FromRGBA32F<PixelOrderBGR>,
+ storeRGB30FromRGBA32F<PixelOrderBGR>,
+ storeRGB30FromRGBA32F<PixelOrderRGB>,
+ storeRGB30FromRGBA32F<PixelOrderRGB>,
+ storeGenericFromRGBA32F<QImage::Format_Alpha8>,
+ storeGenericFromRGBA32F<QImage::Format_Grayscale8>,
+ storeRGBX64FromRGBA32F,
+ storeRGBA64FromRGBA32F,
+ storeRGBA64PMFromRGBA32F,
+ storeGray16FromRGBA32F,
+ storeGenericFromRGBA32F<QImage::Format_BGR888>,
+ storeRGBX16FFromRGBA32F,
+ storeRGBA16FFromRGBA32F,
+ storeRGBA16FPMFromRGBA32F,
+ storeRGBX32FFromRGBA32F,
+ storeRGBA32FFromRGBA32F,
+ storeRGBA32FPMFromRGBA32F,
+ storeCMYKFromRGBA32F,
+};
+
+static_assert(std::size(qStoreFromRGBA32F) == QImage::NImageFormats);
+
+#endif // QT_CONFIG(raster_fp)
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpixellayout_p.h b/src/gui/painting/qpixellayout_p.h
index 0cbf514ded..14f19f4e74 100644
--- a/src/gui/painting/qpixellayout_p.h
+++ b/src/gui/painting/qpixellayout_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPIXELLAYOUT_P_H
#define QPIXELLAYOUT_P_H
@@ -54,6 +18,8 @@
#include <QtCore/qlist.h>
#include <QtGui/qimage.h>
#include <QtGui/qrgba64.h>
+#include <QtGui/qrgbafloat.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -77,7 +43,7 @@ inline QRgb qRepremultiply(QRgb p)
if (alpha == 255 || alpha == 0)
return p;
p = qUnpremultiply(p);
- Q_CONSTEXPR uint mult = 255 / (255 >> Shift);
+ constexpr uint mult = 255 / (255 >> Shift);
const uint newAlpha = mult * (alpha >> Shift);
p = (p & ~0xff000000) | (newAlpha<<24);
return qPremultiply(p);
@@ -90,7 +56,7 @@ inline QRgba64 qRepremultiply(QRgba64 p)
if (alpha == 65535 || alpha == 0)
return p;
p = p.unpremultiplied();
- Q_CONSTEXPR uint mult = 65535 / (65535 >> Shift);
+ constexpr uint mult = 65535 / (65535 >> Shift);
p.setAlpha(mult * (alpha >> Shift));
return p.premultiplied();
}
@@ -217,6 +183,16 @@ inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c)
return (a << 30) | (r << 20) | (g << 10) | b;
}
+inline constexpr QRgbaFloat16 qConvertRgb64ToRgbaF16(QRgba64 c)
+{
+ return QRgbaFloat16::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+}
+
+inline constexpr QRgbaFloat32 qConvertRgb64ToRgbaF32(QRgba64 c)
+{
+ return QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
+}
+
inline uint qRgbSwapRgb30(uint c)
{
const uint ag = c & 0xc00ffc00;
@@ -225,26 +201,26 @@ inline uint qRgbSwapRgb30(uint c)
}
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) {
+static inline quint32 RGBA2ARGB(quint32 x) {
quint32 rgb = x >> 8;
quint32 a = x << 24;
return a | rgb;
}
-Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) {
+static inline quint32 ARGB2RGBA(quint32 x) {
quint32 rgb = x << 8;
quint32 a = x >> 24;
return a | rgb;
}
#else
-Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) {
+static inline quint32 RGBA2ARGB(quint32 x) {
// RGBA8888 is ABGR32 on little endian.
quint32 ag = x & 0xff00ff00;
quint32 rg = x & 0x00ff00ff;
return ag | (rg << 16) | (rg >> 16);
}
-Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) {
+static inline quint32 ARGB2RGBA(quint32 x) {
return RGBA2ARGB(x);
}
#endif
@@ -296,10 +272,19 @@ typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba6
int count, const QList<QRgb> *clut,
QDitherInfo *dither);
-typedef void(QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QList<QRgb> *clut);
-typedef void(QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QList<QRgb> *clut);
+typedef const QRgbaFloat32 *(QT_FASTCALL *FetchAndConvertPixelsFuncFP)(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
+typedef void (QT_FASTCALL *ConvertAndStorePixelsFuncFP)(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
+typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QList<QRgb> *clut);
+typedef void (QT_FASTCALL *Convert64Func)(QRgba64 *buffer, int count);
+typedef void (QT_FASTCALL *ConvertFPFunc)(QRgbaFloat32 *buffer, int count);
+typedef void (QT_FASTCALL *Convert64ToFPFunc)(QRgbaFloat32 *buffer, const quint64 *src, int count);
+
typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count,
const QList<QRgb> *clut, QDitherInfo *dither);
+typedef const QRgbaFloat32 *(QT_FASTCALL *ConvertToFPFunc)(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count);
typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
@@ -316,6 +301,8 @@ struct QPixelLayout
BPP24,
BPP32,
BPP64,
+ BPP16FPx4,
+ BPP32FPx4,
BPPCount
};
@@ -333,7 +320,13 @@ struct QPixelLayout
extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats];
-extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
+#if QT_CONFIG(raster_fp)
+extern ConvertToFPFunc qConvertToRGBA32F[];
+extern FetchAndConvertPixelsFuncFP qFetchToRGBA32F[];
+extern ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[];
+#endif
+
+extern QPixelLayout qPixelLayouts[];
extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 743c183475..f7c4df40c8 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -1,45 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qplatformbackingstore.h"
#include <qwindow.h>
#include <qpixmap.h>
+#include <private/qbackingstorerhisupport_p.h>
+#include <private/qbackingstoredefaultcompositor_p.h>
+#include <private/qwindow_p.h>
#include <QtCore/private/qobject_p.h>
@@ -56,31 +23,27 @@ public:
{
}
- ~QPlatformBackingStorePrivate()
- {
-#ifndef QT_NO_OPENGL
- delete openGLSupport;
-#endif
- }
QWindow *window;
QBackingStore *backingStore;
-#ifndef QT_NO_OPENGL
- QPlatformBackingStoreOpenGLSupportBase *openGLSupport = nullptr;
-#endif
-};
-#ifndef QT_NO_OPENGL
+ // The order matters. if it needs to be rearranged in the future, call
+ // reset() explicitly from the dtor in the correct order.
+ // (first the compositor, then the rhiSupport)
+ QBackingStoreRhiSupport rhiSupport;
+ QBackingStoreDefaultCompositor compositor;
+};
struct QBackingstoreTextureInfo
{
void *source; // may be null
- GLuint textureId;
+ QRhiTexture *texture;
+ QRhiTexture *textureExtra;
QRect rect;
QRect clipRect;
QPlatformTextureList::Flags flags;
};
-Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_RELOCATABLE_TYPE);
class QPlatformTextureListPrivate : public QObjectPrivate
{
@@ -90,7 +53,7 @@ public:
{
}
- QVector<QBackingstoreTextureInfo> textures;
+ QList<QBackingstoreTextureInfo> textures;
bool locked;
};
@@ -106,13 +69,19 @@ QPlatformTextureList::~QPlatformTextureList()
int QPlatformTextureList::count() const
{
Q_D(const QPlatformTextureList);
- return d->textures.count();
+ return d->textures.size();
+}
+
+QRhiTexture *QPlatformTextureList::texture(int index) const
+{
+ Q_D(const QPlatformTextureList);
+ return d->textures.at(index).texture;
}
-GLuint QPlatformTextureList::textureId(int index) const
+QRhiTexture *QPlatformTextureList::textureExtra(int index) const
{
Q_D(const QPlatformTextureList);
- return d->textures.at(index).textureId;
+ return d->textures.at(index).textureExtra;
}
void *QPlatformTextureList::source(int index)
@@ -154,13 +123,29 @@ bool QPlatformTextureList::isLocked() const
return d->locked;
}
-void QPlatformTextureList::appendTexture(void *source, GLuint textureId, const QRect &geometry,
+void QPlatformTextureList::appendTexture(void *source, QRhiTexture *texture, const QRect &geometry,
const QRect &clipRect, Flags flags)
{
Q_D(QPlatformTextureList);
QBackingstoreTextureInfo bi;
bi.source = source;
- bi.textureId = textureId;
+ bi.texture = texture;
+ bi.textureExtra = nullptr;
+ bi.rect = geometry;
+ bi.clipRect = clipRect;
+ bi.flags = flags;
+ d->textures.append(bi);
+}
+
+void QPlatformTextureList::appendTexture(void *source, QRhiTexture *textureLeft, QRhiTexture *textureRight, const QRect &geometry,
+ const QRect &clipRect, Flags flags)
+{
+ Q_D(QPlatformTextureList);
+
+ QBackingstoreTextureInfo bi;
+ bi.source = source;
+ bi.texture = textureLeft;
+ bi.textureExtra = textureRight;
bi.rect = geometry;
bi.clipRect = clipRect;
bi.flags = flags;
@@ -172,7 +157,6 @@ void QPlatformTextureList::clear()
Q_D(QPlatformTextureList);
d->textures.clear();
}
-#endif // QT_NO_OPENGL
/*!
\class QPlatformBackingStore
@@ -185,60 +169,81 @@ void QPlatformTextureList::clear()
windows.
*/
-#ifndef QT_NO_OPENGL
/*!
- Flushes the given \a region from the specified \a window onto the
- screen, and composes it with the specified \a textures.
-
- The default implementation retrieves the contents using toTexture()
- and composes using OpenGL. May be reimplemented in subclasses if there
- is a more efficient native way to do it.
+ Flushes the given \a region from the specified \a window.
\note \a region is relative to the window which may not be top-level in case
\a window corresponds to a native child widget. \a offset is the position of
the native child relative to the top-level window.
+
+ Unlike rhiFlush(), this function's default implementation does nothing. It
+ is expected that subclasses provide a platform-specific (non-QRhi-based)
+ implementation, if applicable on the given platform.
+
+ \sa rhiFlush()
*/
+void QPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+}
+
+/*!
+ Flushes the given \a region from the specified \a window, and compositing
+ it with the specified \a textures list.
+
+ The default implementation retrieves the contents using toTexture() and
+ composes using QRhi with OpenGL, Metal, Vulkan, or Direct 3D underneath.
+ May be reimplemented in subclasses if customization is desired.
+
+ \note \a region is relative to the window which may not be top-level in case
+ \a window corresponds to a native child widget. \a offset is the position of
+ the native child relative to the top-level window.
-void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &region,
- const QPoint &offset,
- QPlatformTextureList *textures,
- bool translucentBackground)
+ \sa flush()
+ */
+QPlatformBackingStore::FlushResult QPlatformBackingStore::rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground)
{
- if (auto *c = d_ptr->openGLSupport)
- c->composeAndFlush(window, region, offset, textures, translucentBackground);
- else
- qWarning() << Q_FUNC_INFO << "no opengl support set";
+ return d_ptr->compositor.flush(this, d_ptr->rhiSupport.rhi(), d_ptr->rhiSupport.swapChainForWindow(window),
+ window, sourceDevicePixelRatio, region, offset, textures, translucentBackground);
}
-#endif
/*!
Implemented in subclasses to return the content of the backingstore as a QImage.
- If QPlatformIntegration::RasterGLSurface is supported, either this function or
+ If composition via a 3D graphics API is supported, either this function or
toTexture() must be implemented.
+ The returned image is only valid until the next operation (resize, paint, scroll,
+ or flush) on the backingstore. The caller must not store the return value between
+ calls, but instead call this function before each use, or make an explicit copy.
+
\sa toTexture()
*/
QImage QPlatformBackingStore::toImage() const
{
return QImage();
}
-#ifndef QT_NO_OPENGL
+
/*!
May be reimplemented in subclasses to return the content of the
- backingstore as an OpenGL texture. \a dirtyRegion is the part of the
+ backingstore as an QRhiTexture. \a dirtyRegion is the part of the
backingstore which may have changed since the last call to this function. The
caller of this function must ensure that there is a current context.
- The size of the texture is returned in \a textureSize.
-
The ownership of the texture is not transferred. The caller must not store
the return value between calls, but instead call this function before each use.
- The default implementation returns a cached texture if \a dirtyRegion is empty and
- \a textureSize matches the backingstore size, otherwise it retrieves the content using
- toImage() and performs a texture upload. This works only if the value of \a textureSize
- is preserved between the calls to this function.
+ The default implementation returns a cached texture if \a dirtyRegion is
+ empty and the existing texture's size matches the backingstore size,
+ otherwise it retrieves the content using toImage() and performs a texture
+ upload.
If the red and blue components have to swapped, \a flags will be set to include \c
TextureSwizzle. This allows creating textures from images in formats like
@@ -252,16 +257,12 @@ QImage QPlatformBackingStore::toImage() const
\note \a dirtyRegion is relative to the backingstore so no adjustment is needed.
*/
-GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const
+QRhiTexture *QPlatformBackingStore::toTexture(QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ TextureFlags *flags) const
{
- if (auto *c = d_ptr->openGLSupport)
- return c->toTexture(dirtyRegion, textureSize, flags);
- else {
- qWarning() << Q_FUNC_INFO << "no opengl support set";
- return 0;
- }
+ return d_ptr->compositor.toTexture(this, d_ptr->rhiSupport.rhi(), resourceUpdates, dirtyRegion, flags);
}
-#endif // QT_NO_OPENGL
/*!
\fn QPaintDevice* QPlatformBackingStore::paintDevice()
@@ -275,12 +276,6 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu
QPlatformBackingStore::QPlatformBackingStore(QWindow *window)
: d_ptr(new QPlatformBackingStorePrivate(window))
{
-#ifndef QT_NO_OPENGL
- if (auto createOpenGLSupport = QPlatformBackingStoreOpenGLSupportBase::factoryFunction()) {
- d_ptr->openGLSupport = createOpenGLSupport();
- d_ptr->openGLSupport->backingStore = this;
- }
-#endif
}
/*!
@@ -317,30 +312,6 @@ QBackingStore *QPlatformBackingStore::backingStore() const
return d_ptr->backingStore;
}
-#ifndef QT_NO_OPENGL
-
-using FactoryFunction = QPlatformBackingStoreOpenGLSupportBase::FactoryFunction;
-
-/*!
- Registers a factory function for OpenGL implementation helper.
-
- The QtOpenGL library automatically registers a default function,
- unless already set by the platform plugin in other ways.
-*/
-void QPlatformBackingStoreOpenGLSupportBase::setFactoryFunction(FactoryFunction function)
-{
- s_factoryFunction = function;
-}
-
-FactoryFunction QPlatformBackingStoreOpenGLSupportBase::factoryFunction()
-{
- return s_factoryFunction;
-}
-
-FactoryFunction QPlatformBackingStoreOpenGLSupportBase::s_factoryFunction = nullptr;
-
-#endif // QT_NO_OPENGL
-
/*!
This function is called before painting onto the surface begins,
with the \a region in which the painting will occur.
@@ -385,4 +356,36 @@ bool QPlatformBackingStore::scroll(const QRegion &area, int dx, int dy)
return false;
}
+void QPlatformBackingStore::setRhiConfig(const QPlatformBackingStoreRhiConfig &config)
+{
+ if (!config.isEnabled())
+ return;
+
+ d_ptr->rhiSupport.setConfig(config);
+ d_ptr->rhiSupport.setWindow(d_ptr->window);
+ d_ptr->rhiSupport.setFormat(d_ptr->window->format());
+ d_ptr->rhiSupport.create();
+}
+
+QRhi *QPlatformBackingStore::rhi() const
+{
+ // Returning null is valid, and means this is not a QRhi-capable backingstore.
+ return d_ptr->rhiSupport.rhi();
+}
+
+void QPlatformBackingStore::graphicsDeviceReportedLost()
+{
+ if (!d_ptr->rhiSupport.rhi())
+ return;
+
+ qWarning("Rhi backingstore: graphics device lost, attempting to reinitialize");
+ d_ptr->compositor.reset();
+ d_ptr->rhiSupport.reset();
+ d_ptr->rhiSupport.create();
+ if (!d_ptr->rhiSupport.rhi())
+ qWarning("Rhi backingstore: failed to reinitialize after losing the device");
+}
+
QT_END_NAMESPACE
+
+#include "moc_qplatformbackingstore.cpp"
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index e0fdca2f21..1d55e9ab6a 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPLATFORMBACKINGSTORE_H
#define QPLATFORMBACKINGSTORE_H
@@ -56,11 +20,10 @@
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
-#include <QtGui/qopengl.h>
QT_BEGIN_NAMESPACE
-Q_GUI_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore)
+Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcQpaBackingStore, Q_GUI_EXPORT)
class QRegion;
class QRect;
@@ -70,9 +33,58 @@ class QPlatformBackingStorePrivate;
class QPlatformTextureList;
class QPlatformTextureListPrivate;
class QPlatformGraphicsBuffer;
-class QPlatformBackingStoreOpenGLSupportBase;
+class QRhi;
+class QRhiTexture;
+class QRhiResourceUpdateBatch;
+
+struct Q_GUI_EXPORT QPlatformBackingStoreRhiConfig
+{
+ enum Api {
+ OpenGL,
+ Metal,
+ Vulkan,
+ D3D11,
+ D3D12,
+ Null
+ };
+
+ QPlatformBackingStoreRhiConfig()
+ : m_enable(false)
+ { }
+
+ QPlatformBackingStoreRhiConfig(Api api)
+ : m_enable(true),
+ m_api(api)
+ { }
+
+ bool isEnabled() const { return m_enable; }
+ void setEnabled(bool enable) { m_enable = enable; }
+
+ Api api() const { return m_api; }
+ void setApi(Api api) { m_api = api; }
+
+ bool isDebugLayerEnabled() const { return m_debugLayer; }
+ void setDebugLayer(bool enable) { m_debugLayer = enable; }
+
+private:
+ bool m_enable;
+ Api m_api = Null;
+ bool m_debugLayer = false;
+ friend bool operator==(const QPlatformBackingStoreRhiConfig &a, const QPlatformBackingStoreRhiConfig &b);
+};
+
+inline bool operator==(const QPlatformBackingStoreRhiConfig &a, const QPlatformBackingStoreRhiConfig &b)
+{
+ return a.m_enable == b.m_enable
+ && a.m_api == b.m_api
+ && a.m_debugLayer == b.m_debugLayer;
+}
+
+inline bool operator!=(const QPlatformBackingStoreRhiConfig &a, const QPlatformBackingStoreRhiConfig &b)
+{
+ return !(a == b);
+}
-#ifndef QT_NO_OPENGL
class Q_GUI_EXPORT QPlatformTextureList : public QObject
{
Q_OBJECT
@@ -81,7 +93,8 @@ public:
enum Flag {
StacksOnTop = 0x01,
TextureIsSrgb = 0x02,
- NeedsPremultipliedAlphaBlending = 0x04
+ NeedsPremultipliedAlphaBlending = 0x04,
+ MirrorVertically = 0x08
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -90,7 +103,8 @@ public:
int count() const;
bool isEmpty() const { return count() == 0; }
- GLuint textureId(int index) const;
+ QRhiTexture *texture(int index) const;
+ QRhiTexture *textureExtra(int index) const;
QRect geometry(int index) const;
QRect clipRect(int index) const;
void *source(int index);
@@ -98,7 +112,10 @@ public:
void lock(bool on);
bool isLocked() const;
- void appendTexture(void *source, GLuint textureId, const QRect &geometry,
+ void appendTexture(void *source, QRhiTexture *texture, const QRect &geometry,
+ const QRect &clipRect = QRect(), Flags flags = { });
+
+ void appendTexture(void *source, QRhiTexture *textureLeft, QRhiTexture *textureRight, const QRect &geometry,
const QRect &clipRect = QRect(), Flags flags = { });
void clear();
@@ -106,11 +123,16 @@ public:
void locked(bool);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformTextureList::Flags)
-#endif
class Q_GUI_EXPORT QPlatformBackingStore
{
public:
+ enum FlushResult {
+ FlushSuccess,
+ FlushFailed,
+ FlushFailedDueToLostDevice
+ };
+
explicit QPlatformBackingStore(QWindow *window);
virtual ~QPlatformBackingStore();
@@ -119,22 +141,26 @@ public:
virtual QPaintDevice *paintDevice() = 0;
- virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset) = 0;
-#ifndef QT_NO_OPENGL
- virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+
+ virtual FlushResult rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
QPlatformTextureList *textures,
bool translucentBackground);
-#endif
+
virtual QImage toImage() const;
-#ifndef QT_NO_OPENGL
+
enum TextureFlag {
TextureSwizzle = 0x01,
TextureFlip = 0x02,
- TexturePremultiplied = 0x04,
+ TexturePremultiplied = 0x04
};
Q_DECLARE_FLAGS(TextureFlags, TextureFlag)
- virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const;
-#endif
+ virtual QRhiTexture *toTexture(QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ TextureFlags *flags) const;
virtual QPlatformGraphicsBuffer *graphicsBuffer() const;
@@ -145,6 +171,11 @@ public:
virtual void beginPaint(const QRegion &);
virtual void endPaint();
+ void setRhiConfig(const QPlatformBackingStoreRhiConfig &config);
+ QRhi *rhi() const;
+ void surfaceAboutToBeDestroyed();
+ void graphicsDeviceReportedLost();
+
private:
QPlatformBackingStorePrivate *d_ptr;
@@ -152,31 +183,7 @@ private:
friend class QBackingStore;
};
-#ifndef QT_NO_OPENGL
-class Q_GUI_EXPORT QPlatformBackingStoreOpenGLSupportBase
-{
-public:
- virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
- QPlatformTextureList *textures, bool translucentBackground) = 0;
- virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, QPlatformBackingStore::TextureFlags *flags) const = 0;
- virtual ~QPlatformBackingStoreOpenGLSupportBase() {}
-
- using FactoryFunction = QPlatformBackingStoreOpenGLSupportBase *(*)();
- static void setFactoryFunction(FactoryFunction);
- static FactoryFunction factoryFunction();
-
-protected:
- QPlatformBackingStore *backingStore = nullptr;
- friend class QPlatformBackingStore;
-
-private:
- static FactoryFunction s_factoryFunction;
-};
-#endif // QT_NO_OPENGL
-
-#ifndef QT_NO_OPENGL
Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformBackingStore::TextureFlags)
-#endif
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpolygon.cpp b/src/gui/painting/qpolygon.cpp
index e9a8793bd0..d615245eb4 100644
--- a/src/gui/painting/qpolygon.cpp
+++ b/src/gui/painting/qpolygon.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpolygon.h"
#include "qrect.h"
@@ -84,7 +48,7 @@ static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QP
/*!
\class QPolygon
- \brief The QPolygon class provides a vector of points using
+ \brief The QPolygon class provides a list of points using
integer precision.
\inmodule QtGui
@@ -93,13 +57,13 @@ static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QP
\ingroup painting
\ingroup shared
- A QPolygon object is a QVector<QPoint>. The easiest way to add
- points to a QPolygon is to use QVector's streaming operator, as
+ A QPolygon object is a QList<QPoint>. The easiest way to add
+ points to a QPolygon is to use QList's streaming operator, as
illustrated below:
\snippet polygon/polygon.cpp 0
- In addition to the functions provided by QVector, QPolygon
+ In addition to the functions provided by QList, QPolygon
provides some point-specific functions.
Each point in a polygon can be retrieved by passing its index to
@@ -117,7 +81,7 @@ static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QP
The QPolygon class is \l {Implicit Data Sharing}{implicitly
shared}.
- \sa QVector, QPolygonF, QLine
+ \sa QList, QPolygonF, QLine
*/
@@ -130,28 +94,11 @@ static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QP
Constructs a polygon with no points.
- \sa QVector::isEmpty()
+ \sa QList::isEmpty()
*/
/*!
- \fn QPolygon::QPolygon(int size)
-
- Constructs a polygon of the given \a size. Creates an empty
- polygon if \a size == 0.
-
- \sa QVector::isEmpty()
-*/
-
-/*!
- \fn QPolygon::QPolygon(const QPolygon &polygon)
-
- Constructs a copy of the given \a polygon.
-
- \sa setPoints()
-*/
-
-/*!
- \fn QPolygon::QPolygon(const QVector<QPoint> &points)
+ \fn QPolygon::QPolygon(const QList<QPoint> &points)
Constructs a polygon containing the specified \a points.
@@ -197,14 +144,6 @@ QPolygon::QPolygon(int nPoints, const int *points)
setPoints(nPoints, points);
}
-
-/*!
- \fn QPolygon::~QPolygon()
-
- Destroys the polygon.
-*/
-
-
/*!
Translates all points in the polygon by (\a{dx}, \a{dy}).
@@ -288,13 +227,16 @@ void QPolygon::point(int index, int *x, int *y) const
*/
/*!
- \fn void QPolygon::setPoint(int index, int x, int y)
-
Sets the point at the given \a index to the point specified by
(\a{x}, \a{y}).
\sa point(), putPoints(), setPoints(),
*/
+void QPolygon::setPoint(int index, int x, int y)
+{
+ (*this)[index] = QPoint(x, y);
+}
+
/*!
Resizes the polygon to \a nPoints and populates it with the given
@@ -438,7 +380,7 @@ void QPolygon::putPoints(int index, int nPoints, const QPolygon & from, int from
Returns the bounding rectangle of the polygon, or QRect(0, 0, 0,
0) if the polygon is empty.
- \sa QVector::isEmpty()
+ \sa QList::isEmpty()
*/
QRect QPolygon::boundingRect() const
@@ -464,22 +406,27 @@ QRect QPolygon::boundingRect() const
return QRect(QPoint(minx,miny), QPoint(maxx,maxy));
}
+/*!
+ \fn QPolygon::toPolygonF() const
+ \since 6.4
+
+ Returns this polygon as a polygon with floating point accuracy.
+
+ \sa QPolygonF::toPolygon()
+*/
+
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QPolygon &a)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QPolygon(";
- for (int i = 0; i < a.count(); ++i)
- dbg.nospace() << a.at(i);
- dbg.nospace() << ')';
- return dbg;
+ return QtPrivate::printSequentialContainer(dbg, "QPolygon", a);
}
#endif
/*!
\class QPolygonF
- \brief The QPolygonF class provides a vector of points using
+ \brief The QPolygonF class provides a list of points using
floating point precision.
\inmodule QtGui
@@ -487,13 +434,13 @@ QDebug operator<<(QDebug dbg, const QPolygon &a)
\ingroup painting
\ingroup shared
- A QPolygonF is a QVector<QPointF>. The easiest way to add points
+ A QPolygonF is a QList<QPointF>. The easiest way to add points
to a QPolygonF is to use its streaming operator, as illustrated
below:
\snippet polygon/polygon.cpp 1
- In addition to the functions provided by QVector, QPolygonF
+ In addition to the functions provided by QList, QPolygonF
provides the boundingRect() and translate() functions for geometry
operations. Use the QTransform::map() function for more general
transformations of QPolygonFs.
@@ -506,7 +453,7 @@ QDebug operator<<(QDebug dbg, const QPolygon &a)
The QPolygonF class is \l {Implicit Data Sharing}{implicitly
shared}.
- \sa QVector, QPolygon, QLineF
+ \sa QList, QPolygon, QLineF
*/
@@ -519,26 +466,11 @@ QDebug operator<<(QDebug dbg, const QPolygon &a)
Constructs a polygon with no points.
- \sa QVector::isEmpty()
+ \sa QList::isEmpty()
*/
/*!
- \fn QPolygonF::QPolygonF(int size)
-
- Constructs a polygon of the given \a size. Creates an empty
- polygon if \a size == 0.
-
- \sa QVector::isEmpty()
-*/
-
-/*!
- \fn QPolygonF::QPolygonF(const QPolygonF &polygon)
-
- Constructs a copy of the given \a polygon.
-*/
-
-/*!
- \fn QPolygonF::QPolygonF(const QVector<QPointF> &points)
+ \fn QPolygonF::QPolygonF(const QList<QPointF> &points)
Constructs a polygon containing the specified \a points.
*/
@@ -581,13 +513,6 @@ QPolygonF::QPolygonF(const QPolygon &a)
}
/*!
- \fn QPolygonF::~QPolygonF()
-
- Destroys the polygon.
-*/
-
-
-/*!
Translate all points in the polygon by the given \a offset.
\sa translated()
@@ -645,14 +570,14 @@ QPolygonF QPolygonF::translated(const QPointF &offset) const
A polygon is said to be closed if its start point and end point are equal.
- \sa QVector::first(), QVector::last()
+ \sa QList::first(), QList::last()
*/
/*!
Returns the bounding rectangle of the polygon, or QRectF(0,0,0,0)
if the polygon is empty.
- \sa QVector::isEmpty()
+ \sa QList::isEmpty()
*/
QRectF QPolygonF::boundingRect() const
@@ -716,7 +641,7 @@ QPolygon QPolygonF::toPolygon() const
*/
QPolygon::operator QVariant() const
{
- return QVariant(QMetaType::QPolygon, this);
+ return QVariant::fromValue(*this);
}
/*****************************************************************************
@@ -735,7 +660,7 @@ QPolygon::operator QVariant() const
*/
QDataStream &operator<<(QDataStream &s, const QPolygon &a)
{
- const QVector<QPoint> &v = a;
+ const QList<QPoint> &v = a;
return s << v;
}
@@ -751,7 +676,7 @@ QDataStream &operator<<(QDataStream &s, const QPolygon &a)
*/
QDataStream &operator>>(QDataStream &s, QPolygon &a)
{
- QVector<QPoint> &v = a;
+ QList<QPoint> &v = a;
return s >> v;
}
#endif // QT_NO_DATASTREAM
@@ -772,13 +697,7 @@ QDataStream &operator>>(QDataStream &s, QPolygon &a)
QDataStream &operator<<(QDataStream &s, const QPolygonF &a)
{
- quint32 len = a.size();
- uint i;
-
- s << len;
- for (i = 0; i < len; ++i)
- s << a.at(i);
- return s;
+ return s << static_cast<const QList<QPointF> &>(a);
}
/*!
@@ -793,29 +712,14 @@ QDataStream &operator<<(QDataStream &s, const QPolygonF &a)
QDataStream &operator>>(QDataStream &s, QPolygonF &a)
{
- quint32 len;
- uint i;
-
- s >> len;
- a.reserve(a.size() + (int)len);
- QPointF p;
- for (i = 0; i < len; ++i) {
- s >> p;
- a.insert(i, p);
- }
- return s;
+ return s >> static_cast<QList<QPointF> &>(a);
}
#endif //QT_NO_DATASTREAM
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QPolygonF &a)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QPolygonF(";
- for (int i = 0; i < a.count(); ++i)
- dbg.nospace() << a.at(i);
- dbg.nospace() << ')';
- return dbg;
+ return QtPrivate::printSequentialContainer(dbg, "QPolygonF", a);
}
#endif
@@ -1040,7 +944,7 @@ bool QPolygonF::intersects(const QPolygonF &p) const
QPolygonF::operator QVariant() const
{
- return QVariant(QMetaType::QPolygonF, this);
+ return QVariant::fromValue(*this);
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpolygon.h b/src/gui/painting/qpolygon.h
index 57c9a3fa46..f2f5d48395 100644
--- a/src/gui/painting/qpolygon.h
+++ b/src/gui/painting/qpolygon.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPOLYGON_H
#define QPOLYGON_H
@@ -51,54 +15,53 @@ class QTransform;
class QRect;
class QVariant;
-class Q_GUI_EXPORT QPolygon : public QList<QPoint>
+class QPolygonF;
+
+// We export each out-of-line method individually to prevent MSVC from
+// exporting the whole QList class.
+class QPolygon : public QList<QPoint>
{
public:
- inline QPolygon() {}
- inline ~QPolygon() {}
- inline explicit QPolygon(int size);
- inline /*implicit*/ QPolygon(const QList<QPoint> &v) : QList<QPoint>(v) { }
- /*implicit*/ QPolygon(QList<QPoint> &&v) noexcept : QList<QPoint>(std::move(v)) { }
- QPolygon(const QRect &r, bool closed=false);
- QPolygon(int nPoints, const int *points);
- QPolygon(const QPolygon &other) : QList<QPoint>(other) { }
- QPolygon(QPolygon &&other) noexcept : QList<QPoint>(std::move(other)) { }
- QPolygon &operator=(QPolygon &&other) noexcept { swap(other); return *this; }
- QPolygon &operator=(const QPolygon &other) { QList<QPoint>::operator=(other); return *this; }
+ using QList<QPoint>::QList;
+ QPolygon() = default;
+ Q_IMPLICIT QPolygon(const QList<QPoint> &v) : QList<QPoint>(v) { }
+ Q_IMPLICIT QPolygon(QList<QPoint> &&v) noexcept : QList<QPoint>(std::move(v)) { }
+ Q_IMPLICIT Q_GUI_EXPORT QPolygon(const QRect &r, bool closed=false);
+ Q_GUI_EXPORT QPolygon(int nPoints, const int *points);
void swap(QPolygon &other) noexcept { QList<QPoint>::swap(other); } // prevent QList<QPoint><->QPolygon swaps
- operator QVariant() const;
+ Q_GUI_EXPORT operator QVariant() const;
- void translate(int dx, int dy);
+ Q_GUI_EXPORT void translate(int dx, int dy);
void translate(const QPoint &offset);
- Q_REQUIRED_RESULT QPolygon translated(int dx, int dy) const;
- Q_REQUIRED_RESULT inline QPolygon translated(const QPoint &offset) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygon translated(int dx, int dy) const;
+ [[nodiscard]] inline QPolygon translated(const QPoint &offset) const;
- QRect boundingRect() const;
+ Q_GUI_EXPORT QRect boundingRect() const;
- void point(int i, int *x, int *y) const;
+ Q_GUI_EXPORT void point(int i, int *x, int *y) const;
QPoint point(int i) const;
- void setPoint(int index, int x, int y);
- void setPoint(int index, const QPoint &p);
- void setPoints(int nPoints, const int *points);
- void setPoints(int nPoints, int firstx, int firsty, ...);
- void putPoints(int index, int nPoints, const int *points);
- void putPoints(int index, int nPoints, int firstx, int firsty, ...);
- void putPoints(int index, int nPoints, const QPolygon & from, int fromIndex=0);
+ Q_GUI_EXPORT void setPoint(int index, int x, int y);
+ inline void setPoint(int index, const QPoint &p);
+ Q_GUI_EXPORT void setPoints(int nPoints, const int *points);
+ Q_GUI_EXPORT void setPoints(int nPoints, int firstx, int firsty, ...);
+ Q_GUI_EXPORT void putPoints(int index, int nPoints, const int *points);
+ Q_GUI_EXPORT void putPoints(int index, int nPoints, int firstx, int firsty, ...);
+ Q_GUI_EXPORT void putPoints(int index, int nPoints, const QPolygon & from, int fromIndex=0);
+
+ Q_GUI_EXPORT bool containsPoint(const QPoint &pt, Qt::FillRule fillRule) const;
- bool containsPoint(const QPoint &pt, Qt::FillRule fillRule) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygon united(const QPolygon &r) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygon intersected(const QPolygon &r) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygon subtracted(const QPolygon &r) const;
- Q_REQUIRED_RESULT QPolygon united(const QPolygon &r) const;
- Q_REQUIRED_RESULT QPolygon intersected(const QPolygon &r) const;
- Q_REQUIRED_RESULT QPolygon subtracted(const QPolygon &r) const;
+ Q_GUI_EXPORT bool intersects(const QPolygon &r) const;
- bool intersects(const QPolygon &r) const;
+ [[nodiscard]] inline QPolygonF toPolygonF() const;
};
Q_DECLARE_SHARED(QPolygon)
-inline QPolygon::QPolygon(int size) : QList<QPoint>(size) { }
-
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QPolygon &);
#endif
@@ -116,10 +79,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QPolygon &polygon);
*****************************************************************************/
inline void QPolygon::setPoint(int index, const QPoint &pt)
-{ (*this)[index] = pt; }
-
-inline void QPolygon::setPoint(int index, int x, int y)
-{ (*this)[index] = QPoint(x, y); }
+{ setPoint(index, pt.x(), pt.y()); }
inline QPoint QPolygon::point(int index) const
{ return at(index); }
@@ -132,47 +92,42 @@ inline QPolygon QPolygon::translated(const QPoint &offset) const
class QRectF;
-class Q_GUI_EXPORT QPolygonF : public QList<QPointF>
+class QPolygonF : public QList<QPointF>
{
public:
- inline QPolygonF() {}
- inline ~QPolygonF() {}
- inline explicit QPolygonF(int size);
- inline /*implicit*/ QPolygonF(const QList<QPointF> &v) : QList<QPointF>(v) { }
- /* implicit */ QPolygonF(QList<QPointF> &&v) noexcept : QList<QPointF>(std::move(v)) { }
- QPolygonF(const QRectF &r);
- /*implicit*/ QPolygonF(const QPolygon &a);
- inline QPolygonF(const QPolygonF &a) : QList<QPointF>(a) { }
- QPolygonF(QPolygonF &&other) noexcept : QList<QPointF>(std::move(other)) { }
- QPolygonF &operator=(QPolygonF &&other) noexcept { swap(other); return *this; }
- QPolygonF &operator=(const QPolygonF &other) { QList<QPointF>::operator=(other); return *this; }
+ using QList<QPointF>::QList;
+ QPolygonF() = default;
+ Q_IMPLICIT QPolygonF(const QList<QPointF> &v) : QList<QPointF>(v) { }
+ Q_IMPLICIT QPolygonF(QList<QPointF> &&v) noexcept : QList<QPointF>(std::move(v)) { }
+ Q_IMPLICIT Q_GUI_EXPORT QPolygonF(const QRectF &r);
+ Q_IMPLICIT Q_GUI_EXPORT QPolygonF(const QPolygon &a);
inline void swap(QPolygonF &other) { QList<QPointF>::swap(other); } // prevent QList<QPointF><->QPolygonF swaps
- operator QVariant() const;
+ Q_GUI_EXPORT operator QVariant() const;
inline void translate(qreal dx, qreal dy);
- void translate(const QPointF &offset);
+ void Q_GUI_EXPORT translate(const QPointF &offset);
inline QPolygonF translated(qreal dx, qreal dy) const;
- Q_REQUIRED_RESULT QPolygonF translated(const QPointF &offset) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygonF translated(const QPointF &offset) const;
- QPolygon toPolygon() const;
+ QPolygon Q_GUI_EXPORT toPolygon() const;
bool isClosed() const { return !isEmpty() && first() == last(); }
- QRectF boundingRect() const;
+ QRectF Q_GUI_EXPORT boundingRect() const;
- bool containsPoint(const QPointF &pt, Qt::FillRule fillRule) const;
+ Q_GUI_EXPORT bool containsPoint(const QPointF &pt, Qt::FillRule fillRule) const;
- Q_REQUIRED_RESULT QPolygonF united(const QPolygonF &r) const;
- Q_REQUIRED_RESULT QPolygonF intersected(const QPolygonF &r) const;
- Q_REQUIRED_RESULT QPolygonF subtracted(const QPolygonF &r) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygonF united(const QPolygonF &r) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygonF intersected(const QPolygonF &r) const;
+ [[nodiscard]] Q_GUI_EXPORT QPolygonF subtracted(const QPolygonF &r) const;
- bool intersects(const QPolygonF &r) const;
+ Q_GUI_EXPORT bool intersects(const QPolygonF &r) const;
};
Q_DECLARE_SHARED(QPolygonF)
-inline QPolygonF::QPolygonF(int size) : QList<QPointF>(size) { }
+QPolygonF QPolygon::toPolygonF() const { return QPolygonF(*this); }
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QPolygonF &);
diff --git a/src/gui/painting/qpolygonclipper_p.h b/src/gui/painting/qpolygonclipper_p.h
deleted file mode 100644
index 04a31111c9..0000000000
--- a/src/gui/painting/qpolygonclipper_p.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QPOLYGONCLIPPER_P_H
-#define QPOLYGONCLIPPER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtGui/private/qtguiglobal_p.h>
-#include "private/qdatabuffer_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/* based on sutherland-hodgman line-by-line clipping, as described in
- Computer Graphics and Principles */
-template <typename InType, typename OutType, typename CastType> class QPolygonClipper
-{
-public:
- QPolygonClipper() :
- buffer1(0), buffer2(0)
- {
- x1 = y1 = x2 = y2 = 0;
- }
-
- ~QPolygonClipper()
- {
- }
-
- void setBoundingRect(const QRect bounds)
- {
- x1 = bounds.x();
- x2 = bounds.x() + bounds.width();
- y1 = bounds.y();
- y2 = bounds.y() + bounds.height();
- }
-
- QRect boundingRect()
- {
- return QRect(QPoint(x1, y1), QPoint(x2, y2));
- }
-
- inline OutType intersectLeft(const OutType &p1, const OutType &p2)
- {
- OutType t;
- qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x);
- t.x = x1;
- t.y = static_cast<CastType>(p2.y + (x1 - p2.x) * dy);
- return t;
- }
-
-
- inline OutType intersectRight(const OutType &p1, const OutType &p2)
- {
- OutType t;
- qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x);
- t.x = x2;
- t.y = static_cast<CastType>(p2.y + (x2 - p2.x) * dy);
- return t;
- }
-
-
- inline OutType intersectTop(const OutType &p1, const OutType &p2)
- {
- OutType t;
- qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y);
- t.x = static_cast<CastType>(p2.x + (y1 - p2.y) * dx);
- t.y = y1;
- return t;
- }
-
-
- inline OutType intersectBottom(const OutType &p1, const OutType &p2)
- {
- OutType t;
- qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y);
- t.x = static_cast<CastType>(p2.x + (y2 - p2.y) * dx);
- t.y = y2;
- return t;
- }
-
-
- void clipPolygon(const InType *inPoints, int inCount, OutType **outPoints, int *outCount,
- bool closePolygon = true)
- {
- Q_ASSERT(outPoints);
- Q_ASSERT(outCount);
-
- if (inCount < 2) {
- *outCount = 0;
- return;
- }
-
- buffer1.reset();
- buffer2.reset();
-
- QDataBuffer<OutType> *source = &buffer1;
- QDataBuffer<OutType> *clipped = &buffer2;
-
- // Gather some info since we are iterating through the points anyway..
- bool doLeft = false, doRight = false, doTop = false, doBottom = false;
- OutType ot;
- for (int i=0; i<inCount; ++i) {
- ot = inPoints[i];
- clipped->add(ot);
-
- if (ot.x < x1)
- doLeft = true;
- else if (ot.x > x2)
- doRight = true;
- if (ot.y < y1)
- doTop = true;
- else if (ot.y > y2)
- doBottom = true;
- }
-
- if (doLeft && clipped->size() > 1) {
- QDataBuffer<OutType> *tmp = source;
- source = clipped;
- clipped = tmp;
- clipped->reset();
- int lastPos, start;
- if (closePolygon) {
- lastPos = source->size() - 1;
- start = 0;
- } else {
- lastPos = 0;
- start = 1;
- if (source->at(0).x >= x1)
- clipped->add(source->at(0));
- }
- for (int i=start; i<inCount; ++i) {
- const OutType &cpt = source->at(i);
- const OutType &ppt = source->at(lastPos);
-
- if (cpt.x >= x1) {
- if (ppt.x >= x1) {
- clipped->add(cpt);
- } else {
- clipped->add(intersectLeft(cpt, ppt));
- clipped->add(cpt);
- }
- } else if (ppt.x >= x1) {
- clipped->add(intersectLeft(cpt, ppt));
- }
- lastPos = i;
- }
- }
-
- if (doRight && clipped->size() > 1) {
- QDataBuffer<OutType> *tmp = source;
- source = clipped;
- clipped = tmp;
- clipped->reset();
- int lastPos, start;
- if (closePolygon) {
- lastPos = source->size() - 1;
- start = 0;
- } else {
- lastPos = 0;
- start = 1;
- if (source->at(0).x <= x2)
- clipped->add(source->at(0));
- }
- for (int i=start; i<source->size(); ++i) {
- const OutType &cpt = source->at(i);
- const OutType &ppt = source->at(lastPos);
-
- if (cpt.x <= x2) {
- if (ppt.x <= x2) {
- clipped->add(cpt);
- } else {
- clipped->add(intersectRight(cpt, ppt));
- clipped->add(cpt);
- }
- } else if (ppt.x <= x2) {
- clipped->add(intersectRight(cpt, ppt));
- }
-
- lastPos = i;
- }
-
- }
-
- if (doTop && clipped->size() > 1) {
- QDataBuffer<OutType> *tmp = source;
- source = clipped;
- clipped = tmp;
- clipped->reset();
- int lastPos, start;
- if (closePolygon) {
- lastPos = source->size() - 1;
- start = 0;
- } else {
- lastPos = 0;
- start = 1;
- if (source->at(0).y >= y1)
- clipped->add(source->at(0));
- }
- for (int i=start; i<source->size(); ++i) {
- const OutType &cpt = source->at(i);
- const OutType &ppt = source->at(lastPos);
-
- if (cpt.y >= y1) {
- if (ppt.y >= y1) {
- clipped->add(cpt);
- } else {
- clipped->add(intersectTop(cpt, ppt));
- clipped->add(cpt);
- }
- } else if (ppt.y >= y1) {
- clipped->add(intersectTop(cpt, ppt));
- }
-
- lastPos = i;
- }
- }
-
- if (doBottom && clipped->size() > 1) {
- QDataBuffer<OutType> *tmp = source;
- source = clipped;
- clipped = tmp;
- clipped->reset();
- int lastPos, start;
- if (closePolygon) {
- lastPos = source->size() - 1;
- start = 0;
- } else {
- lastPos = 0;
- start = 1;
- if (source->at(0).y <= y2)
- clipped->add(source->at(0));
- }
- for (int i=start; i<source->size(); ++i) {
- const OutType &cpt = source->at(i);
- const OutType &ppt = source->at(lastPos);
-
- if (cpt.y <= y2) {
- if (ppt.y <= y2) {
- clipped->add(cpt);
- } else {
- clipped->add(intersectBottom(cpt, ppt));
- clipped->add(cpt);
- }
- } else if (ppt.y <= y2) {
- clipped->add(intersectBottom(cpt, ppt));
- }
- lastPos = i;
- }
- }
-
- if (closePolygon && clipped->size() > 0) {
- // close clipped polygon
- if (clipped->at(0).x != clipped->at(clipped->size()-1).x ||
- clipped->at(0).y != clipped->at(clipped->size()-1).y) {
- OutType ot = clipped->at(0);
- clipped->add(ot);
- }
- }
- *outCount = clipped->size();
- *outPoints = clipped->data();
- }
-
-private:
- int x1, x2, y1, y2;
- QDataBuffer<OutType> buffer1;
- QDataBuffer<OutType> buffer2;
-};
-
-QT_END_NAMESPACE
-
-#endif // QPOLYGONCLIPPER_P_H
diff --git a/src/gui/painting/qrangecollection.cpp b/src/gui/painting/qrangecollection.cpp
deleted file mode 100644
index 5fd4ebaa4b..0000000000
--- a/src/gui/painting/qrangecollection.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qrangecollection.h"
-#include "qrangecollection_p.h"
-
-#include <QtCore/qstack.h>
-
-QT_BEGIN_NAMESPACE
-
-void QRangeCollectionPrivate::mergeIntervals()
-{
- const int count = intervals.count();
-
- if (count <= 0)
- return;
-
- std::sort(intervals.begin(), intervals.end());
-
- QStack<QPair<int, int>> stack;
- stack.push(intervals[0]);
-
- for (int i = 1; i < count; i++) {
- QPair<int, int> &top = stack.top();
-
- if (top.second < intervals[i].first)
- stack.push(intervals[i]);
- else if (top.second < intervals[i].second)
- top.second = intervals[i].second;
- }
-
- std::sort(intervals.begin(), intervals.end());
-
- intervals = stack;
-}
-
-/*!
- \class QRangeCollection
- \brief The QRangeCollection class represents a collection of decimal intervals.
- \inmodule QtGui
- \ingroup painting
- \since 6.0
-
- QRangeCollection manages a set of decimal intervals.
-
- Use QPrinter::rangeCollection() to access the collection of page ranges
- associated with a QPrinter.
-*/
-
-QRangeCollection::QRangeCollection()
- : d_ptr(new QRangeCollectionPrivate(this))
-{
-}
-
-/*!
- Destroys the collection.
-*/
-QRangeCollection::~QRangeCollection()
-{
-}
-
-/*!
- Inserts a single number into the collection.
- */
-void QRangeCollection::addPage(int pageNumber)
-{
- Q_D(QRangeCollection);
- if (pageNumber <= 0) {
- qWarning("QRangeCollection::addPage: 'pageNumber' must be greater than 0");
- return;
- }
- d->intervals.append(qMakePair(pageNumber, pageNumber));
- d->mergeIntervals();
-}
-
-/*!
- Inserts a range into the collection.
- */
-void QRangeCollection::addRange(int from, int to)
-{
- Q_D(QRangeCollection);
- if (from <= 0 || to <= 0) {
- qWarning("QRangeCollection::addRange: 'from' and 'to' must be greater than 0");
- return;
- }
- if (to < from) {
- qWarning("QRangeCollection::addRange: 'from' must be less than or equal to 'to'");
- std::swap(from, to);
- }
- d->intervals.append(qMakePair(from, to));
- d->mergeIntervals();
-}
-
-/*!
- Returns a list with the values of the ranges used in this collection.
- */
-QList<QPair<int, int>> QRangeCollection::toList() const
-{
- Q_D(const QRangeCollection);
- return d->intervals.toList();
-}
-
-/*!
- * Removes all ranges from this collection.
- */
-void QRangeCollection::clear()
-{
- Q_D(QRangeCollection);
- d->intervals.clear();
-}
-
-/*!
- Constructs the range collection from a string representation.
-
- \code
- QPrinter printer;
- printer->rangeCollection()->parse("1-3,6-7");
- \endcode
- */
-bool QRangeCollection::parse(const QString &ranges)
-{
- Q_D(QRangeCollection);
- const QStringList items = ranges.split(u',');
- for (const QString &item : items) {
- if (item.isEmpty()) {
- d->intervals.clear();
- return false;
- }
-
- if (item.contains(QLatin1Char('-'))) {
- const QStringList rangeItems = item.split(u'-');
- if (rangeItems.count() != 2) {
- d->intervals.clear();
- return false;
- }
-
- bool ok;
- const int number1 = rangeItems[0].toInt(&ok);
- if (!ok) {
- d->intervals.clear();
- return false;
- }
-
- const int number2 = rangeItems[1].toInt(&ok);
- if (!ok) {
- d->intervals.clear();
- return false;
- }
-
- if (number1 < 1 || number2 < 1 || number2 < number1) {
- d->intervals.clear();
- return false;
- }
-
- d->intervals.append(qMakePair(number1, number2));
-
- } else {
- bool ok;
- const int number = item.toInt(&ok);
- if (!ok) {
- d->intervals.clear();
- return false;
- }
-
- if (number < 1) {
- d->intervals.clear();
- return false;
- }
-
- d->intervals.append(qMakePair(number, number));
- }
- }
-
- d->mergeIntervals();
- return true;
-}
-
-/*!
- Returns the string representation of the ranges in the collection.
- */
-QString QRangeCollection::toString() const
-{
- Q_D(const QRangeCollection);
- QString result;
-
- for (const QPair<int, int> &pair : d->intervals) {
- if (!result.isEmpty())
- result += QLatin1Char(',');
-
- if (pair.first == pair.second)
- result += QString::number(pair.first);
- else
- result += QStringLiteral("%1-%2").arg(pair.first).arg(pair.second);
- }
-
- return result;
-}
-
-/*!
- Returns \c true if the collection contains an occurrence
- or a bounding range of \a pageNumber; otherwise returns
- \c false.
- */
-bool QRangeCollection::contains(int pageNumber) const
-{
- Q_D(const QRangeCollection);
- for (const QPair<int, int> &pair : d->intervals) {
- if (pair.first <= pageNumber && pair.second >= pageNumber)
- return true;
- }
- return false;
-}
-
-/*!
- Returns \c true if the collection is empty; otherwise returns \c false.
-*/
-bool QRangeCollection::isEmpty() const
-{
- Q_D(const QRangeCollection);
- return d->intervals.isEmpty();
-}
-
-/*!
- Returns the index of the first page covered by the range collection.
-*/
-int QRangeCollection::firstPage() const
-{
- Q_D(const QRangeCollection);
- if (d->intervals.isEmpty())
- return 0;
- return d->intervals.first().first;
-}
-
-/*!
- Returns the index of the last page covered by the range collection.
-*/
-int QRangeCollection::lastPage() const
-{
- Q_D(const QRangeCollection);
- if (d->intervals.isEmpty())
- return 0;
- return d->intervals.last().second;
-}
-
-QT_END_NAMESPACE
diff --git a/src/gui/painting/qrangecollection.h b/src/gui/painting/qrangecollection.h
deleted file mode 100644
index b63ceb6b74..0000000000
--- a/src/gui/painting/qrangecollection.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QRANGECOLLECTION_H
-#define QRANGECOLLECTION_H
-
-#include <QtGui/qtguiglobal.h>
-#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qscopedpointer.h>
-
-QT_BEGIN_NAMESPACE
-
-class QRangeCollectionPrivate;
-
-class Q_GUI_EXPORT QRangeCollection
-{
- Q_DECLARE_PRIVATE(QRangeCollection)
-public:
- explicit QRangeCollection();
- ~QRangeCollection();
-
- void addPage(int pageNumber);
- void addRange(int from, int to);
- QList<QPair<int, int>> toList() const;
- void clear();
-
- bool parse(const QString &ranges);
- QString toString() const;
-
- bool contains(const int pageNumber) const;
- bool isEmpty() const;
- int firstPage() const;
- int lastPage() const;
-
-private:
- QScopedPointer<QRangeCollectionPrivate> d_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QRANGECOLLECTION_H
diff --git a/src/gui/painting/qrangecollection_p.h b/src/gui/painting/qrangecollection_p.h
deleted file mode 100644
index 39a52f2a6b..0000000000
--- a/src/gui/painting/qrangecollection_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QRANGECOLLECTION_P_H
-#define QRANGECOLLECTION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-
-#include <QtGui/private/qtguiglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class Q_GUI_EXPORT QRangeCollectionPrivate
-{
- Q_DECLARE_PUBLIC(QRangeCollection)
-public:
- QRangeCollectionPrivate(QRangeCollection *rangeCollection)
- : q_ptr(rangeCollection)
- {
- }
-
- void mergeIntervals();
-
- QList<QPair<int, int>> intervals;
- QRangeCollection *q_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QRANGECOLLECTION_P_H
diff --git a/src/gui/painting/qrasterbackingstore.cpp b/src/gui/painting/qrasterbackingstore.cpp
index a3ffe11d19..3b3ef2fd2e 100644
--- a/src/gui/painting/qrasterbackingstore.cpp
+++ b/src/gui/painting/qrasterbackingstore.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrasterbackingstore_p.h"
@@ -82,7 +46,7 @@ QImage QRasterBackingStore::toImage() const
bool QRasterBackingStore::scroll(const QRegion &region, int dx, int dy)
{
- if (window()->surfaceType() != QSurface::RasterSurface)
+ if (!QPlatformSurface::isRasterSurface(window()))
return false;
extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
@@ -90,8 +54,8 @@ bool QRasterBackingStore::scroll(const QRegion &region, int dx, int dy)
const qreal devicePixelRatio = m_image.devicePixelRatio();
const QPoint delta(dx * devicePixelRatio, dy * devicePixelRatio);
- for (const QRect &rect : region)
- qt_scrollRectInImage(m_image, QRect(rect.topLeft() * devicePixelRatio, rect.size() * devicePixelRatio), delta);
+ const QRect rect = region.boundingRect();
+ qt_scrollRectInImage(m_image, QRect(rect.topLeft() * devicePixelRatio, rect.size() * devicePixelRatio), delta);
return true;
}
@@ -103,7 +67,7 @@ void QRasterBackingStore::beginPaint(const QRegion &region)
if (m_image.devicePixelRatio() != nativeWindowDevicePixelRatio || m_image.size() != effectiveBufferSize) {
m_image = QImage(effectiveBufferSize, format());
m_image.setDevicePixelRatio(nativeWindowDevicePixelRatio);
- if (m_image.format() == QImage::Format_ARGB32_Premultiplied)
+ if (m_image.hasAlphaChannel())
m_image.fill(Qt::transparent);
}
diff --git a/src/gui/painting/qrasterbackingstore_p.h b/src/gui/painting/qrasterbackingstore_p.h
index 01d75c655b..be8d122655 100644
--- a/src/gui/painting/qrasterbackingstore_p.h
+++ b/src/gui/painting/qrasterbackingstore_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRASTERBACKINGSTORE_P_H
#define QRASTERBACKINGSTORE_P_H
@@ -52,6 +16,7 @@
//
#include <qpa/qplatformbackingstore.h>
+#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qrasterdefs_p.h b/src/gui/painting/qrasterdefs_p.h
index bf57a84c24..f6bf3bb0c8 100644
--- a/src/gui/painting/qrasterdefs_p.h
+++ b/src/gui/painting/qrasterdefs_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/***************************************************************************/
/* */
@@ -865,10 +829,10 @@ QT_FT_BEGIN_HEADER
/* */
typedef struct QT_FT_Span_
{
- short x;
- unsigned short len;
- short y;
- unsigned char coverage;
+ int x;
+ int len;
+ int y;
+ unsigned char coverage;
} QT_FT_Span;
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index f3c193d799..cd9d3ba4d0 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrasterizer_p.h"
@@ -52,15 +16,20 @@
QT_BEGIN_NAMESPACE
-typedef int Q16Dot16;
-#define Q16Dot16ToFloat(i) ((i)/65536.)
-#define FloatToQ16Dot16(i) (int)((i) * 65536.)
-#define IntToQ16Dot16(i) ((i) * (1 << 16))
-#define Q16Dot16ToInt(i) ((i) >> 16)
-#define Q16Dot16Factor 65536
-
-#define Q16Dot16Multiply(x, y) (int)((qlonglong(x) * qlonglong(y)) >> 16)
-#define Q16Dot16FastMultiply(x, y) (((x) * (y)) >> 16)
+#if Q_PROCESSOR_WORDSIZE == 8
+typedef qint64 QScFixed;
+#else
+typedef int QScFixed;
+#endif
+#define QScFixedToFloat(i) ((i) * (1./65536.))
+#define FloatToQScFixed(i) (QScFixed)((i) * 65536.)
+#define IntToQScFixed(i) ((QScFixed)(i) * (1 << 16))
+#define QScFixedToInt(i) ((i) >> 16)
+#define QScFixedFactor 65536
+#define FTPosToQScFixed(i) ((QScFixed)(i) * (1 << 10))
+
+#define QScFixedMultiply(x, y) (QScFixed)((qlonglong(x) * qlonglong(y)) >> 16)
+#define QScFixedFastMultiply(x, y) (((x) * (y)) >> 16)
#define SPAN_BUFFER_SIZE 256
@@ -88,11 +57,12 @@ public:
flushSpans();
}
- void addSpan(int x, unsigned int len, int y, unsigned char coverage)
+ void addSpan(int x, int len, int y, int coverage)
{
if (!coverage || !len)
return;
+ Q_ASSERT(coverage >= 0 && coverage <= 255);
Q_ASSERT(y >= m_clipRect.top());
Q_ASSERT(y <= m_clipRect.bottom());
Q_ASSERT(x >= m_clipRect.left());
@@ -131,7 +101,7 @@ public:
~QScanConverter();
void begin(int top, int bottom, int left, int right,
- Qt::FillRule fillRule, bool legacyRounding, QSpanBuffer *spanBuffer);
+ Qt::FillRule fillRule, QSpanBuffer *spanBuffer);
void end();
void mergeCurve(const QT_FT_Vector &a, const QT_FT_Vector &b,
@@ -140,8 +110,8 @@ public:
struct Line
{
- Q16Dot16 x;
- Q16Dot16 delta;
+ QScFixed x;
+ QScFixed delta;
int top, bottom;
@@ -157,7 +127,7 @@ private:
int left, right;
};
- inline bool clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding);
+ inline bool clip(QScFixed &xFP, int &iTop, int &iBottom, QScFixed slopeFP, QScFixed edgeFP, int winding);
inline void mergeIntersection(Intersection *head, const Intersection &isect);
void prepareChunk();
@@ -175,11 +145,10 @@ private:
int m_top;
int m_bottom;
- Q16Dot16 m_leftFP;
- Q16Dot16 m_rightFP;
+ QScFixed m_leftFP;
+ QScFixed m_rightFP;
int m_fillRuleMask;
- bool m_legacyRounding;
int m_x;
int m_y;
@@ -191,15 +160,14 @@ private:
QDataBuffer<Line *> m_active;
- template <typename T>
- friend void qScanConvert(QScanConverter &d, T allVertical);
+ template <bool AllVertical>
+ void scanConvert();
};
class QRasterizerPrivate
{
public:
bool antialiased;
- bool legacyRounding;
ProcessSpans blend;
void *data;
QRect clipRect;
@@ -223,18 +191,17 @@ QScanConverter::~QScanConverter()
}
void QScanConverter::begin(int top, int bottom, int left, int right,
- Qt::FillRule fillRule, bool legacyRounding,
+ Qt::FillRule fillRule,
QSpanBuffer *spanBuffer)
{
m_top = top;
m_bottom = bottom;
- m_leftFP = IntToQ16Dot16(left);
- m_rightFP = IntToQ16Dot16(right + 1);
+ m_leftFP = IntToQScFixed(left);
+ m_rightFP = IntToQScFixed(right + 1);
m_lines.reset();
m_fillRuleMask = fillRule == Qt::WindingFill ? ~0x0 : 0x1;
- m_legacyRounding = legacyRounding;
m_spanBuffer = spanBuffer;
}
@@ -301,71 +268,58 @@ static void split(QT_FT_Vector *b)
}
}
-static inline bool topOrder(const QScanConverter::Line &a, const QScanConverter::Line &b)
-{
- return a.top < b.top;
-}
-
-static inline bool xOrder(const QScanConverter::Line *a, const QScanConverter::Line *b)
-{
- return a->x < b->x;
-}
-
-template <bool B>
-struct QBoolToType
-{
- inline bool operator()() const
- {
- return B;
- }
-};
-
-// should be a member function but VC6 doesn't support member template functions
-template <typename T>
-void qScanConvert(QScanConverter &d, T allVertical)
+template <bool AllVertical>
+void QScanConverter::scanConvert()
{
- if (!d.m_lines.size()) {
- d.m_active.reset();
+ if (!m_lines.size()) {
+ m_active.reset();
return;
}
- std::sort(d.m_lines.data(), d.m_lines.data() + d.m_lines.size(), QT_PREPEND_NAMESPACE(topOrder));
+ constexpr auto topOrder = [](const Line &a, const Line &b) {
+ return a.top < b.top;
+ };
+ constexpr auto xOrder = [](const Line *a, const Line *b) {
+ return a->x < b->x;
+ };
+
+ std::sort(m_lines.data(), m_lines.data() + m_lines.size(), topOrder);
int line = 0;
- for (int y = d.m_lines.first().top; y <= d.m_bottom; ++y) {
- for (; line < d.m_lines.size() && d.m_lines.at(line).top == y; ++line) {
+ for (int y = m_lines.first().top; y <= m_bottom; ++y) {
+ for (; line < m_lines.size() && m_lines.at(line).top == y; ++line) {
// add node to active list
- if (allVertical()) {
- QScanConverter::Line *l = &d.m_lines.at(line);
- d.m_active.resize(d.m_active.size() + 1);
+ if constexpr(AllVertical) {
+ QScanConverter::Line *l = &m_lines.at(line);
+ m_active.resize(m_active.size() + 1);
int j;
- for (j = d.m_active.size() - 2; j >= 0 && QT_PREPEND_NAMESPACE(xOrder)(l, d.m_active.at(j)); --j)
- d.m_active.at(j+1) = d.m_active.at(j);
- d.m_active.at(j+1) = l;
+ for (j = m_active.size() - 2; j >= 0 && xOrder(l, m_active.at(j)); --j)
+ m_active.at(j+1) = m_active.at(j);
+ m_active.at(j+1) = l;
} else {
- d.m_active << &d.m_lines.at(line);
+ m_active << &m_lines.at(line);
}
}
- int numActive = d.m_active.size();
- if (!allVertical()) {
- // use insertion sort instead of qSort, as the active edge list is quite small
- // and in the average case already sorted
+ int numActive = m_active.size();
+ if constexpr(!AllVertical) {
+ // use insertion sort instead of std::sort, as the active edge list is quite small
+ // and in the average case already sorted
for (int i = 1; i < numActive; ++i) {
- QScanConverter::Line *l = d.m_active.at(i);
+ QScanConverter::Line *l = m_active.at(i);
int j;
- for (j = i-1; j >= 0 && QT_PREPEND_NAMESPACE(xOrder)(l, d.m_active.at(j)); --j)
- d.m_active.at(j+1) = d.m_active.at(j);
- d.m_active.at(j+1) = l;
+ for (j = i-1; j >= 0 && xOrder(l, m_active.at(j)); --j)
+ m_active.at(j+1) = m_active.at(j);
+ m_active.at(j+1) = l;
}
}
int x = 0;
int winding = 0;
for (int i = 0; i < numActive; ++i) {
- QScanConverter::Line *node = d.m_active.at(i);
+ QScanConverter::Line *node = m_active.at(i);
- const int current = Q16Dot16ToInt(node->x);
- if (winding & d.m_fillRuleMask)
- d.m_spanBuffer->addSpan(x, current - x, y, 0xff);
+ const int current = QScFixedToInt(node->x);
+ if (winding & m_fillRuleMask)
+ m_spanBuffer->addSpan(x, current - x, y, 0xff);
x = current;
winding += node->winding;
@@ -373,15 +327,17 @@ void qScanConvert(QScanConverter &d, T allVertical)
if (node->bottom == y) {
// remove node from active list
for (int j = i; j < numActive - 1; ++j)
- d.m_active.at(j) = d.m_active.at(j+1);
+ m_active.at(j) = m_active.at(j+1);
- d.m_active.resize(--numActive);
+ m_active.resize(--numActive);
--i;
- } else if (!allVertical())
- node->x += node->delta;
+ } else {
+ if constexpr(!AllVertical)
+ node->x += node->delta;
+ }
}
}
- d.m_active.reset();
+ m_active.reset();
}
void QScanConverter::end()
@@ -398,9 +354,9 @@ void QScanConverter::end()
}
}
if (allVertical)
- qScanConvert(*this, QBoolToType<true>());
+ scanConvert<true>();
else
- qScanConvert(*this, QBoolToType<false>());
+ scanConvert<false>();
} else {
for (int chunkTop = m_top; chunkTop <= m_bottom; chunkTop += CHUNK_SIZE) {
prepareChunk();
@@ -425,12 +381,12 @@ void QScanConverter::end()
if (line.delta) {
for (; it != end; ++it) {
- isect.x = Q16Dot16ToInt(line.x);
+ isect.x = QScFixedToInt(line.x);
line.x += line.delta;
mergeIntersection(it, isect);
}
} else {
- isect.x = Q16Dot16ToInt(line.x);
+ isect.x = QScFixedToInt(line.x);
for (; it != end; ++it)
mergeIntersection(it, isect);
}
@@ -527,7 +483,7 @@ void QScanConverter::mergeCurve(const QT_FT_Vector &pa, const QT_FT_Vector &pb,
}
}
-inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding)
+inline bool QScanConverter::clip(QScFixed &xFP, int &iTop, int &iBottom, QScFixed slopeFP, QScFixed edgeFP, int winding)
{
bool right = edgeFP == m_rightFP;
@@ -541,7 +497,7 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
}
}
- Q16Dot16 lastFP = xFP + slopeFP * (iBottom - iTop);
+ QScFixed lastFP = xFP + slopeFP * (iBottom - iTop);
if (lastFP == edgeFP) {
if ((slopeFP < 0) ^ right)
@@ -555,11 +511,11 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
// does line cross edge?
if ((lastFP < edgeFP) ^ (xFP < edgeFP)) {
- Q16Dot16 deltaY = Q16Dot16((edgeFP - xFP) / Q16Dot16ToFloat(slopeFP));
+ QScFixed deltaY = QScFixed((edgeFP - xFP) / QScFixedToFloat(slopeFP));
if ((xFP < edgeFP) ^ right) {
// top segment needs to be clipped
- int iHeight = Q16Dot16ToInt(deltaY + 1);
+ int iHeight = QScFixedToInt(deltaY + 1);
int iMiddle = iTop + iHeight;
Line line = { edgeFP, 0, iTop, iMiddle, winding };
@@ -572,7 +528,7 @@ inline bool QScanConverter::clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot1
return true;
} else {
// bottom segment needs to be clipped
- int iHeight = Q16Dot16ToInt(deltaY);
+ int iHeight = QScFixedToInt(deltaY);
int iMiddle = iTop + iHeight;
if (iMiddle != iBottom) {
@@ -601,20 +557,11 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
winding = -1;
}
- if (m_legacyRounding) {
- a.x += COORD_OFFSET;
- a.y += COORD_OFFSET;
- b.x += COORD_OFFSET;
- b.y += COORD_OFFSET;
- }
-
- int rounding = m_legacyRounding ? COORD_ROUNDING : 0;
-
- int iTop = qMax(m_top, int((a.y + 32 - rounding) >> 6));
- int iBottom = qMin(m_bottom, int((b.y - 32 - rounding) >> 6));
+ int iTop = qMax(m_top, int((a.y + 32) >> 6));
+ int iBottom = qMin(m_bottom, int((b.y - 32) >> 6));
if (iTop <= iBottom) {
- Q16Dot16 aFP = Q16Dot16Factor/2 + (a.x * (1 << 10)) - rounding;
+ QScFixed aFP = QScFixedFactor/2 + FTPosToQScFixed(a.x);
if (b.x == a.x) {
Line line = { qBound(m_leftFP, aFP, m_rightFP), 0, iTop, iBottom, winding };
@@ -622,11 +569,11 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
} else {
const qreal slope = (b.x - a.x) / qreal(b.y - a.y);
- const Q16Dot16 slopeFP = FloatToQ16Dot16(slope);
+ const QScFixed slopeFP = FloatToQScFixed(slope);
- Q16Dot16 xFP = aFP + Q16Dot16Multiply(slopeFP,
- IntToQ16Dot16(iTop)
- + Q16Dot16Factor/2 - (a.y * (1 << 10)));
+ QScFixed xFP = aFP + QScFixedMultiply(slopeFP,
+ IntToQScFixed(iTop)
+ + QScFixedFactor/2 - FTPosToQScFixed(a.y));
if (clip(xFP, iTop, iBottom, slopeFP, m_leftFP, winding))
return;
@@ -645,7 +592,6 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
QRasterizer::QRasterizer()
: d(new QRasterizerPrivate)
{
- d->legacyRounding = false;
}
QRasterizer::~QRasterizer()
@@ -669,44 +615,44 @@ void QRasterizer::setClipRect(const QRect &clipRect)
d->clipRect = clipRect;
}
-void QRasterizer::setLegacyRoundingEnabled(bool legacyRoundingEnabled)
+static QScFixed intersectPixelFP(int x, QScFixed top, QScFixed bottom, QScFixed leftIntersectX, QScFixed rightIntersectX, QScFixed slope, QScFixed invSlope)
{
- d->legacyRounding = legacyRoundingEnabled;
-}
-
-static Q16Dot16 intersectPixelFP(int x, Q16Dot16 top, Q16Dot16 bottom, Q16Dot16 leftIntersectX, Q16Dot16 rightIntersectX, Q16Dot16 slope, Q16Dot16 invSlope)
-{
- Q16Dot16 leftX = IntToQ16Dot16(x);
- Q16Dot16 rightX = IntToQ16Dot16(x) + Q16Dot16Factor;
+ QScFixed leftX = IntToQScFixed(x);
+ QScFixed rightX = IntToQScFixed(x) + QScFixedFactor;
- Q16Dot16 leftIntersectY, rightIntersectY;
- if (slope > 0) {
- leftIntersectY = top + Q16Dot16Multiply(leftX - leftIntersectX, invSlope);
- rightIntersectY = leftIntersectY + invSlope;
- } else {
- leftIntersectY = top + Q16Dot16Multiply(leftX - rightIntersectX, invSlope);
- rightIntersectY = leftIntersectY + invSlope;
- }
+ QScFixed leftIntersectY, rightIntersectY;
+ auto computeIntersectY = [&]() {
+ if (slope > 0) {
+ leftIntersectY = top + QScFixedMultiply(leftX - leftIntersectX, invSlope);
+ rightIntersectY = leftIntersectY + invSlope;
+ } else {
+ leftIntersectY = top + QScFixedMultiply(leftX - rightIntersectX, invSlope);
+ rightIntersectY = leftIntersectY + invSlope;
+ }
+ };
if (leftIntersectX >= leftX && rightIntersectX <= rightX) {
- return Q16Dot16Multiply(bottom - top, leftIntersectX - leftX + ((rightIntersectX - leftIntersectX) >> 1));
+ return QScFixedMultiply(bottom - top, leftIntersectX - leftX + ((rightIntersectX - leftIntersectX) >> 1));
} else if (leftIntersectX >= rightX) {
return bottom - top;
} else if (leftIntersectX >= leftX) {
+ computeIntersectY();
if (slope > 0) {
- return (bottom - top) - Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, rightIntersectY - top);
+ return (bottom - top) - QScFixedFastMultiply((rightX - leftIntersectX) >> 1, rightIntersectY - top);
} else {
- return (bottom - top) - Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, bottom - rightIntersectY);
+ return (bottom - top) - QScFixedFastMultiply((rightX - leftIntersectX) >> 1, bottom - rightIntersectY);
}
} else if (rightIntersectX <= leftX) {
return 0;
} else if (rightIntersectX <= rightX) {
+ computeIntersectY();
if (slope > 0) {
- return Q16Dot16FastMultiply((rightIntersectX - leftX) >> 1, bottom - leftIntersectY);
+ return QScFixedFastMultiply((rightIntersectX - leftX) >> 1, bottom - leftIntersectY);
} else {
- return Q16Dot16FastMultiply((rightIntersectX - leftX) >> 1, leftIntersectY - top);
+ return QScFixedFastMultiply((rightIntersectX - leftX) >> 1, leftIntersectY - top);
}
} else {
+ computeIntersectY();
if (slope > 0) {
return (bottom - rightIntersectY) + ((rightIntersectY - leftIntersectY) >> 1);
} else {
@@ -745,14 +691,78 @@ static inline qreal qSafeDivide(qreal x, qreal y)
too small to fit into INT_MIN, so we need this slightly safer conversion
when floating point exceptions are enabled
*/
-static inline int qSafeFloatToQ16Dot16(qreal x)
+static inline QScFixed qSafeFloatToQScFixed(qreal x)
{
- qreal tmp = x * 65536.;
+ qreal tmp = x * QScFixedFactor;
+#if Q_PROCESSOR_WORDSIZE == 8
+ if (tmp > qreal(INT_MAX) * QScFixedFactor)
+ return QScFixed(INT_MAX) * QScFixedFactor;
+ else if (tmp < qreal(INT_MIN) * QScFixedFactor)
+ return QScFixed(INT_MIN) * QScFixedFactor;
+#else
if (tmp > qreal(INT_MAX))
return INT_MAX;
else if (tmp < qreal(INT_MIN))
return -INT_MAX;
- return int(tmp);
+#endif
+ return QScFixed(tmp);
+}
+
+// returns true if the whole line gets clipped away
+static inline bool qClipLine(QPointF *pt1, QPointF *pt2, const QRectF &clip)
+{
+ qreal &x1 = pt1->rx();
+ qreal &y1 = pt1->ry();
+ qreal &x2 = pt2->rx();
+ qreal &y2 = pt2->ry();
+
+ if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
+ return true;
+
+ const qreal xmin = clip.left();
+ const qreal xmax = clip.right();
+ const qreal ymin = clip.top();
+ const qreal ymax = clip.bottom();
+
+ if (x1 < xmin) {
+ if (x2 <= xmin)
+ return true;
+ y1 += (y2 - y1) / (x2 - x1) * (xmin - x1);
+ x1 = xmin;
+ } else if (x1 > xmax) {
+ if (x2 >= xmax)
+ return true;
+ y1 += (y2 - y1) / (x2 - x1) * (xmax - x1);
+ x1 = xmax;
+ }
+ if (x2 < xmin) {
+ y2 += (y2 - y1) / (x2 - x1) * (xmin - x2);
+ x2 = xmin;
+ } else if (x2 > xmax) {
+ y2 += (y2 - y1) / (x2 - x1) * (xmax - x2);
+ x2 = xmax;
+ }
+
+ if (y1 < ymin) {
+ if (y2 <= ymin)
+ return true;
+ x1 += (x2 - x1) / (y2 - y1) * (ymin - y1);
+ y1 = ymin;
+ } else if (y1 > ymax) {
+ if (y2 >= ymax)
+ return true;
+ x1 += (x2 - x1) / (y2 - y1) * (ymax - y1);
+ y1 = ymax;
+ }
+ if (y2 < ymin) {
+ x2 += (x2 - x1) / (y2 - y1) * (ymin - y2);
+ y2 = ymin;
+ } else if (y2 > ymax) {
+ x2 += (x2 - x1) / (y2 - y1) * (ymax - y2);
+ y2 = ymax;
+ }
+
+ return false;
}
void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap)
@@ -771,49 +781,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5;
const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs);
-
- if (!clip.contains(pa) || !clip.contains(pb)) {
- qreal t1 = 0;
- qreal t2 = 1;
-
- const qreal o[2] = { pa.x(), pa.y() };
- const qreal d[2] = { pb.x() - pa.x(), pb.y() - pa.y() };
-
- const qreal low[2] = { clip.left(), clip.top() };
- const qreal high[2] = { clip.right(), clip.bottom() };
-
- for (int i = 0; i < 2; ++i) {
- if (d[i] == 0) {
- if (o[i] <= low[i] || o[i] >= high[i])
- return;
- continue;
- }
- const qreal d_inv = 1 / d[i];
- qreal t_low = (low[i] - o[i]) * d_inv;
- qreal t_high = (high[i] - o[i]) * d_inv;
- if (t_low > t_high)
- qSwap(t_low, t_high);
- if (t1 < t_low)
- t1 = t_low;
- if (t2 > t_high)
- t2 = t_high;
- if (t1 >= t2)
- return;
- }
-
- QPointF npa = pa + (pb - pa) * t1;
- QPointF npb = pa + (pb - pa) * t2;
-
- pa = npa;
- pb = npb;
- }
-
- if (!d->antialiased && d->legacyRounding) {
- pa.rx() += (COORD_OFFSET - COORD_ROUNDING)/64.;
- pa.ry() += (COORD_OFFSET - COORD_ROUNDING)/64.;
- pb.rx() += (COORD_OFFSET - COORD_ROUNDING)/64.;
- pb.ry() += (COORD_OFFSET - COORD_ROUNDING)/64.;
- }
+ if (qClipLine(&pa, &pb, clip))
+ return;
{
// old delta
@@ -866,30 +835,33 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
return;
if (d->antialiased) {
- const Q16Dot16 iLeft = int(left);
- const Q16Dot16 iRight = int(right);
- const Q16Dot16 leftWidth = IntToQ16Dot16(iLeft + 1)
- - qSafeFloatToQ16Dot16(left);
- const Q16Dot16 rightWidth = qSafeFloatToQ16Dot16(right)
- - IntToQ16Dot16(iRight);
-
- Q16Dot16 coverage[3];
+ const int iLeft = int(left);
+ const int iRight = int(right);
+ const QScFixed leftWidth = IntToQScFixed(iLeft + 1)
+ - qSafeFloatToQScFixed(left);
+ const QScFixed rightWidth = qSafeFloatToQScFixed(right)
+ - IntToQScFixed(iRight);
+
+ QScFixed coverage[3];
int x[3];
int len[3];
int n = 1;
if (iLeft == iRight) {
- coverage[0] = (leftWidth + rightWidth) * 255;
+ if (leftWidth == QScFixedFactor)
+ coverage[0] = rightWidth * 255;
+ else
+ coverage[0] = (rightWidth + leftWidth - QScFixedFactor) * 255;
x[0] = iLeft;
len[0] = 1;
} else {
coverage[0] = leftWidth * 255;
x[0] = iLeft;
len[0] = 1;
- if (leftWidth == Q16Dot16Factor) {
+ if (leftWidth == QScFixedFactor) {
len[0] = iRight - iLeft;
} else if (iRight - iLeft > 1) {
- coverage[1] = IntToQ16Dot16(255);
+ coverage[1] = IntToQScFixed(255);
x[1] = iLeft + 1;
len[1] = iRight - iLeft - 1;
++n;
@@ -902,19 +874,19 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
}
}
- const Q16Dot16 iTopFP = IntToQ16Dot16(int(pa.y()));
- const Q16Dot16 iBottomFP = IntToQ16Dot16(int(pb.y()));
- const Q16Dot16 yPa = qSafeFloatToQ16Dot16(pa.y());
- const Q16Dot16 yPb = qSafeFloatToQ16Dot16(pb.y());
- for (Q16Dot16 yFP = iTopFP; yFP <= iBottomFP; yFP += Q16Dot16Factor) {
- const Q16Dot16 rowHeight = qMin(yFP + Q16Dot16Factor, yPb)
+ const QScFixed iTopFP = IntToQScFixed(int(pa.y()));
+ const QScFixed iBottomFP = IntToQScFixed(int(pb.y()));
+ const QScFixed yPa = qSafeFloatToQScFixed(pa.y());
+ const QScFixed yPb = qSafeFloatToQScFixed(pb.y());
+ for (QScFixed yFP = iTopFP; yFP <= iBottomFP; yFP += QScFixedFactor) {
+ const QScFixed rowHeight = qMin(yFP + QScFixedFactor, yPb)
- qMax(yFP, yPa);
- const int y = Q16Dot16ToInt(yFP);
+ const int y = QScFixedToInt(yFP);
if (y > d->clipRect.bottom())
break;
for (int i = 0; i < n; ++i) {
buffer.addSpan(x[i], len[i], y,
- Q16Dot16ToInt(Q16Dot16Multiply(rowHeight, coverage[i])));
+ QScFixedToInt(QScFixedMultiply(rowHeight, coverage[i])));
}
}
} else { // aliased
@@ -971,111 +943,111 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
- const Q16Dot16 topLeftSlopeFP = qSafeFloatToQ16Dot16(topLeftSlope);
- const Q16Dot16 topRightSlopeFP = qSafeFloatToQ16Dot16(topRightSlope);
+ const QScFixed topLeftSlopeFP = qSafeFloatToQScFixed(topLeftSlope);
+ const QScFixed topRightSlopeFP = qSafeFloatToQScFixed(topRightSlope);
- const Q16Dot16 bottomLeftSlopeFP = qSafeFloatToQ16Dot16(bottomLeftSlope);
- const Q16Dot16 bottomRightSlopeFP = qSafeFloatToQ16Dot16(bottomRightSlope);
+ const QScFixed bottomLeftSlopeFP = qSafeFloatToQScFixed(bottomLeftSlope);
+ const QScFixed bottomRightSlopeFP = qSafeFloatToQScFixed(bottomRightSlope);
- const Q16Dot16 invTopLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topLeftSlope));
- const Q16Dot16 invTopRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topRightSlope));
+ const QScFixed invTopLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topLeftSlope));
+ const QScFixed invTopRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topRightSlope));
- const Q16Dot16 invBottomLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomLeftSlope));
- const Q16Dot16 invBottomRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomRightSlope));
+ const QScFixed invBottomLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomLeftSlope));
+ const QScFixed invBottomRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomRightSlope));
if (d->antialiased) {
- const Q16Dot16 iTopFP = IntToQ16Dot16(int(topBound));
- const Q16Dot16 iLeftFP = IntToQ16Dot16(int(left.y()));
- const Q16Dot16 iRightFP = IntToQ16Dot16(int(right.y()));
- const Q16Dot16 iBottomFP = IntToQ16Dot16(int(bottomBound));
+ const QScFixed iTopFP = IntToQScFixed(int(topBound));
+ const QScFixed iLeftFP = IntToQScFixed(int(left.y()));
+ const QScFixed iRightFP = IntToQScFixed(int(right.y()));
+ const QScFixed iBottomFP = IntToQScFixed(int(bottomBound));
- Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topLeftSlope);
- Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() + (int(topBound) - top.y()) * topRightSlope);
- Q16Dot16 leftIntersectBf = 0;
- Q16Dot16 rightIntersectBf = 0;
+ QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + (int(topBound) - top.y()) * topLeftSlope);
+ QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() + (int(topBound) - top.y()) * topRightSlope);
+ QScFixed leftIntersectBf = 0;
+ QScFixed rightIntersectBf = 0;
if (iLeftFP < iTopFP)
- leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
+ leftIntersectBf = qSafeFloatToQScFixed(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
if (iRightFP < iTopFP)
- rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
+ rightIntersectBf = qSafeFloatToQScFixed(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
- Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
- Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
- Q16Dot16 bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
+ QScFixed rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
+ QScFixed topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
+ QScFixed bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
int leftMin, leftMax, rightMin, rightMax;
- const Q16Dot16 yTopFP = qSafeFloatToQ16Dot16(top.y());
- const Q16Dot16 yLeftFP = qSafeFloatToQ16Dot16(left.y());
- const Q16Dot16 yRightFP = qSafeFloatToQ16Dot16(right.y());
- const Q16Dot16 yBottomFP = qSafeFloatToQ16Dot16(bottom.y());
+ const QScFixed yTopFP = qSafeFloatToQScFixed(top.y());
+ const QScFixed yLeftFP = qSafeFloatToQScFixed(left.y());
+ const QScFixed yRightFP = qSafeFloatToQScFixed(right.y());
+ const QScFixed yBottomFP = qSafeFloatToQScFixed(bottom.y());
rowTop = qMax(iTopFP, yTopFP);
topLeftIntersectAf = leftIntersectAf +
- Q16Dot16Multiply(topLeftSlopeFP, rowTop - iTopFP);
+ QScFixedMultiply(topLeftSlopeFP, rowTop - iTopFP);
topRightIntersectAf = rightIntersectAf +
- Q16Dot16Multiply(topRightSlopeFP, rowTop - iTopFP);
+ QScFixedMultiply(topRightSlopeFP, rowTop - iTopFP);
- Q16Dot16 yFP = iTopFP;
+ QScFixed yFP = iTopFP;
while (yFP <= iBottomFP) {
- rowBottomLeft = qMin(yFP + Q16Dot16Factor, yLeftFP);
- rowBottomRight = qMin(yFP + Q16Dot16Factor, yRightFP);
+ rowBottomLeft = qMin(yFP + QScFixedFactor, yLeftFP);
+ rowBottomRight = qMin(yFP + QScFixedFactor, yRightFP);
rowTopLeft = qMax(yFP, yLeftFP);
rowTopRight = qMax(yFP, yRightFP);
- rowBottom = qMin(yFP + Q16Dot16Factor, yBottomFP);
+ rowBottom = qMin(yFP + QScFixedFactor, yBottomFP);
if (yFP == iLeftFP) {
- const int y = Q16Dot16ToInt(yFP);
- leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope);
- topLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP);
- bottomLeftIntersectAf = leftIntersectAf + Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP);
+ const int y = QScFixedToInt(yFP);
+ leftIntersectBf = qSafeFloatToQScFixed(left.x() + (y - left.y()) * bottomLeftSlope);
+ topLeftIntersectBf = leftIntersectBf + QScFixedMultiply(bottomLeftSlopeFP, rowTopLeft - yFP);
+ bottomLeftIntersectAf = leftIntersectAf + QScFixedMultiply(topLeftSlopeFP, rowBottomLeft - yFP);
} else {
topLeftIntersectBf = leftIntersectBf;
bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
}
if (yFP == iRightFP) {
- const int y = Q16Dot16ToInt(yFP);
- rightIntersectBf = qSafeFloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope);
- topRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP);
- bottomRightIntersectAf = rightIntersectAf + Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP);
+ const int y = QScFixedToInt(yFP);
+ rightIntersectBf = qSafeFloatToQScFixed(right.x() + (y - right.y()) * bottomRightSlope);
+ topRightIntersectBf = rightIntersectBf + QScFixedMultiply(bottomRightSlopeFP, rowTopRight - yFP);
+ bottomRightIntersectAf = rightIntersectAf + QScFixedMultiply(topRightSlopeFP, rowBottomRight - yFP);
} else {
topRightIntersectBf = rightIntersectBf;
bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
}
if (yFP == iBottomFP) {
- bottomLeftIntersectBf = leftIntersectBf + Q16Dot16Multiply(bottomLeftSlopeFP, rowBottom - yFP);
- bottomRightIntersectBf = rightIntersectBf + Q16Dot16Multiply(bottomRightSlopeFP, rowBottom - yFP);
+ bottomLeftIntersectBf = leftIntersectBf + QScFixedMultiply(bottomLeftSlopeFP, rowBottom - yFP);
+ bottomRightIntersectBf = rightIntersectBf + QScFixedMultiply(bottomRightSlopeFP, rowBottom - yFP);
} else {
bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
}
if (yFP < iLeftFP) {
- leftMin = Q16Dot16ToInt(bottomLeftIntersectAf);
- leftMax = Q16Dot16ToInt(topLeftIntersectAf);
+ leftMin = QScFixedToInt(bottomLeftIntersectAf);
+ leftMax = QScFixedToInt(topLeftIntersectAf);
} else if (yFP == iLeftFP) {
- leftMin = Q16Dot16ToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
- leftMax = Q16Dot16ToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
+ leftMin = QScFixedToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
+ leftMax = QScFixedToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
} else {
- leftMin = Q16Dot16ToInt(topLeftIntersectBf);
- leftMax = Q16Dot16ToInt(bottomLeftIntersectBf);
+ leftMin = QScFixedToInt(topLeftIntersectBf);
+ leftMax = QScFixedToInt(bottomLeftIntersectBf);
}
leftMin = qBound(d->clipRect.left(), leftMin, d->clipRect.right());
leftMax = qBound(d->clipRect.left(), leftMax, d->clipRect.right());
if (yFP < iRightFP) {
- rightMin = Q16Dot16ToInt(topRightIntersectAf);
- rightMax = Q16Dot16ToInt(bottomRightIntersectAf);
+ rightMin = QScFixedToInt(topRightIntersectAf);
+ rightMax = QScFixedToInt(bottomRightIntersectAf);
} else if (yFP == iRightFP) {
- rightMin = Q16Dot16ToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
- rightMax = Q16Dot16ToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
+ rightMin = QScFixedToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
+ rightMax = QScFixedToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
} else {
- rightMin = Q16Dot16ToInt(bottomRightIntersectBf);
- rightMax = Q16Dot16ToInt(topRightIntersectBf);
+ rightMin = QScFixedToInt(bottomRightIntersectBf);
+ rightMax = QScFixedToInt(topRightIntersectBf);
}
rightMin = qBound(d->clipRect.left(), rightMin, d->clipRect.right());
@@ -1086,56 +1058,57 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
if (rightMin < leftMin)
rightMin = leftMin;
- Q16Dot16 rowHeight = rowBottom - rowTop;
+ QScFixed rowHeight = rowBottom - rowTop;
int x = leftMin;
while (x <= leftMax) {
- Q16Dot16 excluded = 0;
+ QScFixed excluded = 0;
- if (yFP <= iLeftFP)
+ if (yFP <= iLeftFP && rowBottomLeft > rowTop)
excluded += intersectPixelFP(x, rowTop, rowBottomLeft,
bottomLeftIntersectAf, topLeftIntersectAf,
topLeftSlopeFP, invTopLeftSlopeFP);
- if (yFP >= iLeftFP)
+ if (yFP >= iLeftFP && rowBottom > rowTopLeft)
excluded += intersectPixelFP(x, rowTopLeft, rowBottom,
topLeftIntersectBf, bottomLeftIntersectBf,
bottomLeftSlopeFP, invBottomLeftSlopeFP);
-
if (x >= rightMin) {
- if (yFP <= iRightFP)
+ if (yFP <= iRightFP && rowBottomRight > rowTop)
excluded += (rowBottomRight - rowTop) - intersectPixelFP(x, rowTop, rowBottomRight,
topRightIntersectAf, bottomRightIntersectAf,
topRightSlopeFP, invTopRightSlopeFP);
- if (yFP >= iRightFP)
+ if (yFP >= iRightFP && rowBottom > rowTopRight)
excluded += (rowBottom - rowTopRight) - intersectPixelFP(x, rowTopRight, rowBottom,
bottomRightIntersectBf, topRightIntersectBf,
bottomRightSlopeFP, invBottomRightSlopeFP);
}
- Q16Dot16 coverage = rowHeight - excluded;
- buffer.addSpan(x, 1, Q16Dot16ToInt(yFP),
- Q16Dot16ToInt(255 * coverage));
+ Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
+ QScFixed coverage = rowHeight - excluded;
+ buffer.addSpan(x, 1, QScFixedToInt(yFP),
+ QScFixedToInt(255 * coverage));
++x;
}
if (x < rightMin) {
- buffer.addSpan(x, rightMin - x, Q16Dot16ToInt(yFP),
- Q16Dot16ToInt(255 * rowHeight));
+ buffer.addSpan(x, rightMin - x, QScFixedToInt(yFP),
+ QScFixedToInt(255 * rowHeight));
x = rightMin;
}
while (x <= rightMax) {
- Q16Dot16 excluded = 0;
- if (yFP <= iRightFP)
+ QScFixed excluded = 0;
+ if (yFP <= iRightFP && rowBottomRight > rowTop)
excluded += (rowBottomRight - rowTop) - intersectPixelFP(x, rowTop, rowBottomRight,
topRightIntersectAf, bottomRightIntersectAf,
topRightSlopeFP, invTopRightSlopeFP);
- if (yFP >= iRightFP)
+ if (yFP >= iRightFP && rowBottom > rowTopRight)
excluded += (rowBottom - rowTopRight) - intersectPixelFP(x, rowTopRight, rowBottom,
bottomRightIntersectBf, topRightIntersectBf,
bottomRightSlopeFP, invBottomRightSlopeFP);
- Q16Dot16 coverage = rowHeight - excluded;
- buffer.addSpan(x, 1, Q16Dot16ToInt(yFP),
- Q16Dot16ToInt(255 * coverage));
+ Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
+ QScFixed coverage = rowHeight - excluded;
+ buffer.addSpan(x, 1, QScFixedToInt(yFP),
+ QScFixedToInt(255 * coverage));
++x;
}
@@ -1146,7 +1119,7 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
topLeftIntersectAf = leftIntersectAf;
topRightIntersectAf = rightIntersectAf;
- yFP += Q16Dot16Factor;
+ yFP += QScFixedFactor;
rowTop = yFP;
}
} else { // aliased
@@ -1156,10 +1129,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
int iBottom = bottom.y() < 0.5f? -1 : int(bottom.y() - 0.5f);
int iMiddle = qMin(iLeft, iRight);
- Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
- Q16Dot16 leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
- Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
- Q16Dot16 rightIntersectBf = qSafeFloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
+ QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
+ QScFixed leftIntersectBf = qSafeFloatToQScFixed(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
+ QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
+ QScFixed rightIntersectBf = qSafeFloatToQScFixed(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
int ny;
int y = iTop;
@@ -1173,8 +1146,8 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
if (next > d->clipRect.bottom()) \
next = d->clipRect.bottom(); \
for (; y <= next; ++y) { \
- const int x1 = qMax(Q16Dot16ToInt(li), d->clipRect.left()); \
- const int x2 = qMin(Q16Dot16ToInt(ri), d->clipRect.right()); \
+ const int x1 = qMax(QScFixedToInt(li), d->clipRect.left()); \
+ const int x2 = qMin(QScFixedToInt(ri), d->clipRect.right()); \
if (x2 >= x1) \
buffer.addSpan(x1, x2 - x1 + 1, y, 255); \
li += ls; \
@@ -1209,15 +1182,13 @@ void QRasterizer::rasterize(const QT_FT_Outline *outline, Qt::FillRule fillRule)
max_y = qMax(p.y, max_y);
}
- int rounding = d->legacyRounding ? COORD_OFFSET - COORD_ROUNDING : 0;
-
- int iTopBound = qMax(d->clipRect.top(), int((min_y + 32 + rounding) >> 6));
- int iBottomBound = qMin(d->clipRect.bottom(), int((max_y - 32 + rounding) >> 6));
+ int iTopBound = qMax(d->clipRect.top(), int((min_y + 32) >> 6));
+ int iBottomBound = qMin(d->clipRect.bottom(), int((max_y - 32) >> 6));
if (iTopBound > iBottomBound)
return;
- d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, d->legacyRounding, &buffer);
+ d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, &buffer);
int first = 0;
for (int i = 0; i < outline->n_contours; ++i) {
@@ -1247,15 +1218,13 @@ void QRasterizer::rasterize(const QPainterPath &path, Qt::FillRule fillRule)
QRectF bounds = path.controlPointRect();
- double rounding = d->legacyRounding ? (COORD_OFFSET - COORD_ROUNDING) / 64. : 0.0;
-
- int iTopBound = qMax(d->clipRect.top(), int(bounds.top() + 0.5 + rounding));
- int iBottomBound = qMin(d->clipRect.bottom(), int(bounds.bottom() - 0.5 + rounding));
+ int iTopBound = qMax(d->clipRect.top(), int(bounds.top() + 0.5));
+ int iBottomBound = qMin(d->clipRect.bottom(), int(bounds.bottom() - 0.5));
if (iTopBound > iBottomBound)
return;
- d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, d->legacyRounding, &buffer);
+ d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, &buffer);
int subpathStart = 0;
QT_FT_Vector last = { 0, 0 };
diff --git a/src/gui/painting/qrasterizer_p.h b/src/gui/painting/qrasterizer_p.h
index 955577f4a3..f12ab1b812 100644
--- a/src/gui/painting/qrasterizer_p.h
+++ b/src/gui/painting/qrasterizer_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRASTERIZER_P_H
#define QRASTERIZER_P_H
@@ -72,7 +36,6 @@ public:
void setAntialiased(bool antialiased);
void setClipRect(const QRect &clipRect);
- void setLegacyRoundingEnabled(bool legacyRoundingEnabled);
void initialize(ProcessSpans blend, void *data);
diff --git a/src/gui/painting/qrbtree_p.h b/src/gui/painting/qrbtree_p.h
index 42539bf8e9..e42c4081f6 100644
--- a/src/gui/painting/qrbtree_p.h
+++ b/src/gui/painting/qrbtree_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRBTREE_P_H
#define QRBTREE_P_H
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 8021b17c6b..8b712ee46d 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qregion.h"
#include "qpainterpath.h"
@@ -48,8 +12,13 @@
#include "qbitmap.h"
#include "qtransform.h"
+#include <memory>
#include <private/qdebug_p.h>
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -82,7 +51,7 @@ QT_BEGIN_NAMESPACE
contains() a QPoint or QRect. The bounding rectangle can be found
with boundingRect().
- Iteration over the region (with begin(), end(), or C++11
+ Iteration over the region (with begin(), end(), or
ranged-for loops) gives a decomposition of the region into
rectangles.
@@ -130,7 +99,7 @@ QT_BEGIN_NAMESPACE
\fn QRegion::QRegion(const QRect &r, RegionType t)
\overload
- Create a region based on the rectange \a r with region type \a t.
+ Create a region based on the rectangle \a r with region type \a t.
If the rectangle is invalid a null region will be created.
@@ -296,7 +265,7 @@ void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byt
quint32 n;
s >> n;
QRect r;
- for (int i=0; i<(int)n; i++) {
+ for (int i=0; i < static_cast<int>(n); i++) {
s >> r;
rgn = rgn.united(QRegion(r));
}
@@ -345,19 +314,19 @@ QDataStream &operator<<(QDataStream &s, const QRegion &r)
{
auto b = r.begin(), e = r.end();
if (b == e) {
- s << (quint32)0;
+ s << static_cast<quint32>(0);
} else {
const auto size = e - b;
if (s.version() == 1) {
for (auto i = size - 1; i > 0; --i) {
- s << (quint32)(12 + i * 24);
- s << (int)QRGN_OR;
+ s << static_cast<quint32>(12 + i * 24);
+ s << static_cast<int>(QRGN_OR);
}
for (auto it = b; it != e; ++it)
- s << (quint32)(4+8) << (int)QRGN_SETRECT << *it;
+ s << static_cast<quint32>(4+8) << static_cast<int>(QRGN_SETRECT) << *it;
} else {
s << quint32(4 + 4 + 16 * size); // 16: storage size of QRect
- s << (qint32)QRGN_RECTS;
+ s << static_cast<qint32>(QRGN_RECTS);
s << quint32(size);
for (auto it = b; it != e; ++it)
s << *it;
@@ -579,7 +548,7 @@ QRegion& QRegion::operator^=(const QRegion &r)
*/
QRegion::operator QVariant() const
{
- return QVariant(QMetaType::QRegion, this);
+ return QVariant::fromValue(*this);
}
/*!
@@ -667,7 +636,7 @@ bool QRegion::intersects(const QRegion &region) const
*/
-#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_CLANG_QDOC)
+#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_QDOC)
/*
\overload
\since 4.4
@@ -1101,7 +1070,7 @@ Q_GUI_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
struct QRegionPrivate {
int numRects;
int innerArea;
- QVector<QRect> rects;
+ QList<QRect> rects;
QRect extents;
QRect innerRect;
@@ -2173,7 +2142,7 @@ static void miRegionOp(QRegionPrivate &dest,
* reg1->rects and reg2->rects (if the regions have more than 1 rectangle),
* take a copy of dest.rects to keep those iteractors valid.
*/
- const QVector<QRect> destRectsCopy = dest.rects;
+ const QList<QRect> destRectsCopy = dest.rects;
Q_UNUSED(destRectsCopy);
dest.numRects = 0;
@@ -3222,8 +3191,7 @@ static void CreateETandAET(int count, const QPoint *pts,
int iSLLBlock = 0;
int dy;
- if (count < 2)
- return;
+ Q_ASSERT(count > 1);
/*
* initialize the Active Edge Table
@@ -3565,9 +3533,12 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
int fixWAET = false;
POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
+ FirstPtBlock.next = nullptr;
POINTBLOCK *tmpPtBlock;
int numFullPtBlocks = 0;
+ Q_ASSERT(Count > 1);
+
region = new QRegionPrivate;
/* special case a rectangle */
@@ -3846,7 +3817,7 @@ QRegion::QRegion(const QRect &r, RegionType t)
QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
{
- if (a.count() > 2) {
+ if (a.size() > 2) {
QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
if (qt_rgn) {
@@ -3908,7 +3879,7 @@ QRegion &QRegion::operator=(const QRegion &r)
QRegion QRegion::copy() const
{
QRegion r;
- QScopedPointer<QRegionData> x(new QRegionData);
+ auto x = std::make_unique<QRegionData>();
x->ref.initializeOwned();
if (d->qt_rgn)
x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
@@ -3916,7 +3887,7 @@ QRegion QRegion::copy() const
x->qt_rgn = new QRegionPrivate;
if (!r.d->ref.deref())
cleanUp(r.d);
- r.d = x.take();
+ r.d = x.release();
return r;
}
@@ -4314,4 +4285,65 @@ bool QRegion::intersects(const QRect &rect) const
#endif
+
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+
+static inline HRGN qt_RectToHRGN(const QRect &rc)
+{
+ return CreateRectRgn(rc.left(), rc.top(), rc.right() + 1, rc.bottom() + 1);
+}
+
+/*!
+ \since 6.0
+
+ Returns a HRGN that is equivalent to the given region.
+*/
+HRGN QRegion::toHRGN() const
+{
+ const int size = rectCount();
+ if (size == 0)
+ return nullptr;
+
+ HRGN resultRgn = nullptr;
+ const auto rects = begin();
+ resultRgn = qt_RectToHRGN(rects[0]);
+ for (int i = 1; i < size; ++i) {
+ HRGN tmpRgn = qt_RectToHRGN(rects[i]);
+ int err = CombineRgn(resultRgn, resultRgn, tmpRgn, RGN_OR);
+ if (err == ERROR)
+ qWarning("Error combining HRGNs.");
+ DeleteObject(tmpRgn);
+ }
+ return resultRgn;
+}
+
+/*!
+ \since 6.0
+
+ Returns a QRegion that is equivalent to the given \a hrgn.
+ */
+QRegion QRegion::fromHRGN(HRGN hrgn)
+{
+ DWORD regionDataSize = GetRegionData(hrgn, 0, nullptr);
+ if (regionDataSize == 0)
+ return QRegion();
+
+ auto regionData = reinterpret_cast<LPRGNDATA>(malloc(regionDataSize));
+ if (!regionData)
+ return QRegion();
+
+ QRegion region;
+ if (GetRegionData(hrgn, regionDataSize, regionData) == regionDataSize) {
+ auto pRect = reinterpret_cast<LPRECT>(regionData->Buffer);
+ for (DWORD i = 0; i < regionData->rdh.nCount; ++i)
+ region += QRect(pRect[i].left, pRect[i].top,
+ pRect[i].right - pRect[i].left,
+ pRect[i].bottom - pRect[i].top);
+ }
+
+ free(regionData);
+ return region;
+}
+#endif // Q_OS_WIN || Q_QDOC
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h
index 49174e7510..b0051b6067 100644
--- a/src/gui/painting/qregion.h
+++ b/src/gui/painting/qregion.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QREGION_H
#define QREGION_H
@@ -70,13 +34,12 @@ public:
QRegion(const QPolygon &pa, Qt::FillRule fillRule = Qt::OddEvenFill);
QRegion(const QRegion &region);
QRegion(QRegion &&other) noexcept
- : d(other.d) { other.d = const_cast<QRegionData*>(&shared_empty); }
+ : d(std::exchange(other.d, const_cast<QRegionData*>(&shared_empty))) {}
QRegion(const QBitmap &bitmap);
~QRegion();
QRegion &operator=(const QRegion &);
- inline QRegion &operator=(QRegion &&other) noexcept
- { qSwap(d, other.d); return *this; }
- inline void swap(QRegion &other) noexcept { qSwap(d, other.d); }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRegion)
+ void swap(QRegion &other) noexcept { qt_ptr_swap(d, other.d); }
bool isEmpty() const;
bool isNull() const;
@@ -97,15 +60,15 @@ public:
void translate(int dx, int dy);
inline void translate(const QPoint &p) { translate(p.x(), p.y()); }
- Q_REQUIRED_RESULT QRegion translated(int dx, int dy) const;
- Q_REQUIRED_RESULT inline QRegion translated(const QPoint &p) const { return translated(p.x(), p.y()); }
+ [[nodiscard]] QRegion translated(int dx, int dy) const;
+ [[nodiscard]] inline QRegion translated(const QPoint &p) const { return translated(p.x(), p.y()); }
- Q_REQUIRED_RESULT QRegion united(const QRegion &r) const;
- Q_REQUIRED_RESULT QRegion united(const QRect &r) const;
- Q_REQUIRED_RESULT QRegion intersected(const QRegion &r) const;
- Q_REQUIRED_RESULT QRegion intersected(const QRect &r) const;
- Q_REQUIRED_RESULT QRegion subtracted(const QRegion &r) const;
- Q_REQUIRED_RESULT QRegion xored(const QRegion &r) const;
+ [[nodiscard]] QRegion united(const QRegion &r) const;
+ [[nodiscard]] QRegion united(const QRect &r) const;
+ [[nodiscard]] QRegion intersected(const QRegion &r) const;
+ [[nodiscard]] QRegion intersected(const QRect &r) const;
+ [[nodiscard]] QRegion subtracted(const QRegion &r) const;
+ [[nodiscard]] QRegion xored(const QRegion &r) const;
bool intersects(const QRegion &r) const;
bool intersects(const QRect &r) const;
@@ -134,6 +97,12 @@ public:
inline bool operator!=(const QRegion &r) const { return !(operator==(r)); }
operator QVariant() const;
+ // Platform specific conversion functions
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+ HRGN toHRGN() const;
+ static QRegion fromHRGN(HRGN hrgn);
+#endif
+
#ifndef QT_NO_DATASTREAM
friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QRegion &);
friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QRegion &);
diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h
index fe8306109b..150d889d33 100644
--- a/src/gui/painting/qrgb.h
+++ b/src/gui/painting/qrgb.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRGB_H
#define QRGB_H
@@ -49,36 +13,36 @@ QT_BEGIN_NAMESPACE
typedef unsigned int QRgb; // RGB triplet
// non-namespaced Qt global variable
-const Q_DECL_UNUSED QRgb RGB_MASK = 0x00ffffff; // masks RGB values
+ inline constexpr QRgb RGB_MASK = 0x00ffffff; // masks RGB values
-inline Q_DECL_CONSTEXPR int qRed(QRgb rgb) // get red part of RGB
+inline constexpr int qRed(QRgb rgb) // get red part of RGB
{ return ((rgb >> 16) & 0xff); }
-inline Q_DECL_CONSTEXPR int qGreen(QRgb rgb) // get green part of RGB
+inline constexpr int qGreen(QRgb rgb) // get green part of RGB
{ return ((rgb >> 8) & 0xff); }
-inline Q_DECL_CONSTEXPR int qBlue(QRgb rgb) // get blue part of RGB
+inline constexpr int qBlue(QRgb rgb) // get blue part of RGB
{ return (rgb & 0xff); }
-inline Q_DECL_CONSTEXPR int qAlpha(QRgb rgb) // get alpha part of RGBA
+inline constexpr int qAlpha(QRgb rgb) // get alpha part of RGBA
{ return rgb >> 24; }
-inline Q_DECL_CONSTEXPR QRgb qRgb(int r, int g, int b)// set RGB value
+inline constexpr QRgb qRgb(int r, int g, int b) // set RGB value
{ return (0xffu << 24) | ((r & 0xffu) << 16) | ((g & 0xffu) << 8) | (b & 0xffu); }
-inline Q_DECL_CONSTEXPR QRgb qRgba(int r, int g, int b, int a)// set RGBA value
+inline constexpr QRgb qRgba(int r, int g, int b, int a) // set RGBA value
{ return ((a & 0xffu) << 24) | ((r & 0xffu) << 16) | ((g & 0xffu) << 8) | (b & 0xffu); }
-inline Q_DECL_CONSTEXPR int qGray(int r, int g, int b)// convert R,G,B to gray 0..255
+inline constexpr int qGray(int r, int g, int b) // convert R,G,B to gray 0..255
{ return (r*11+g*16+b*5)/32; }
-inline Q_DECL_CONSTEXPR int qGray(QRgb rgb) // convert RGB to gray 0..255
+inline constexpr int qGray(QRgb rgb) // convert RGB to gray 0..255
{ return qGray(qRed(rgb), qGreen(rgb), qBlue(rgb)); }
-inline Q_DECL_CONSTEXPR bool qIsGray(QRgb rgb)
+inline constexpr bool qIsGray(QRgb rgb)
{ return qRed(rgb) == qGreen(rgb) && qRed(rgb) == qBlue(rgb); }
-inline Q_DECL_RELAXED_CONSTEXPR QRgb qPremultiply(QRgb x)
+inline constexpr QRgb qPremultiply(QRgb x)
{
const uint a = qAlpha(x);
uint t = (x & 0xff00ff) * a;
diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h
index 30d5e244b8..9c0c210320 100644
--- a/src/gui/painting/qrgba64.h
+++ b/src/gui/painting/qrgba64.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRGBA64_H
#define QRGBA64_H
@@ -64,16 +28,16 @@ class QRgba64 {
#endif
};
- explicit Q_ALWAYS_INLINE Q_DECL_CONSTEXPR QRgba64(quint64 c) : rgba(c) { }
+ explicit Q_ALWAYS_INLINE constexpr QRgba64(quint64 c) : rgba(c) { }
public:
QRgba64() = default;
- Q_DECL_CONSTEXPR static
+ constexpr static
QRgba64 fromRgba64(quint64 c)
{
return QRgba64(c);
}
- Q_DECL_CONSTEXPR static
+ constexpr static
QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
{
return fromRgba64(quint64(red) << RedShift
@@ -81,44 +45,43 @@ public:
| quint64(blue) << BlueShift
| quint64(alpha) << AlphaShift);
}
- Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+ constexpr static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
{
QRgba64 rgb64 = fromRgba64(red, green, blue, alpha);
// Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff.
rgb64.rgba |= rgb64.rgba << 8;
return rgb64;
}
- Q_DECL_RELAXED_CONSTEXPR static
+ constexpr static
QRgba64 fromArgb32(uint rgb)
{
return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24));
}
- Q_DECL_CONSTEXPR bool isOpaque() const
+ constexpr bool isOpaque() const
{
return (rgba & alphaMask()) == alphaMask();
}
- Q_DECL_CONSTEXPR bool isTransparent() const
+ constexpr bool isTransparent() const
{
return (rgba & alphaMask()) == 0;
}
- Q_DECL_CONSTEXPR quint16 red() const { return quint16(rgba >> RedShift); }
- Q_DECL_CONSTEXPR quint16 green() const { return quint16(rgba >> GreenShift); }
- Q_DECL_CONSTEXPR quint16 blue() const { return quint16(rgba >> BlueShift); }
- Q_DECL_CONSTEXPR quint16 alpha() const { return quint16(rgba >> AlphaShift); }
+ constexpr quint16 red() const { return quint16(rgba >> RedShift); }
+ constexpr quint16 green() const { return quint16(rgba >> GreenShift); }
+ constexpr quint16 blue() const { return quint16(rgba >> BlueShift); }
+ constexpr quint16 alpha() const { return quint16(rgba >> AlphaShift); }
void setRed(quint16 _red) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << RedShift)) | (quint64(_red) << RedShift); }
void setGreen(quint16 _green) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << GreenShift)) | (quint64(_green) << GreenShift); }
void setBlue(quint16 _blue) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << BlueShift)) | (quint64(_blue) << BlueShift); }
void setAlpha(quint16 _alpha) { rgba = (rgba & ~(Q_UINT64_C(0xffff) << AlphaShift)) | (quint64(_alpha) << AlphaShift); }
- Q_DECL_CONSTEXPR quint8 red8() const { return div_257(red()); }
- Q_DECL_CONSTEXPR quint8 green8() const { return div_257(green()); }
- Q_DECL_CONSTEXPR quint8 blue8() const { return div_257(blue()); }
- Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(alpha()); }
- Q_DECL_CONSTEXPR uint toArgb32() const
+ constexpr quint8 red8() const { return div_257(red()); }
+ constexpr quint8 green8() const { return div_257(green()); }
+ constexpr quint8 blue8() const { return div_257(blue()); }
+ constexpr quint8 alpha8() const { return div_257(alpha()); }
+ constexpr uint toArgb32() const
{
-#if defined(__cpp_constexpr) && __cpp_constexpr-0 >= 201304
quint64 br = rgba & Q_UINT64_C(0xffff0000ffff);
quint64 ag = (rgba >> 16) & Q_UINT64_C(0xffff0000ffff);
br += Q_UINT64_C(0x8000000080);
@@ -136,16 +99,13 @@ public:
| (ag & 0xff00)
| ((br >> 32) & 0xff);
#endif
-#else
- return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8());
-#endif
}
- Q_DECL_CONSTEXPR ushort toRgb16() const
+ constexpr ushort toRgb16() const
{
return ushort((red() & 0xf800) | ((green() >> 10) << 5) | (blue() >> 11));
}
- Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const
+ constexpr QRgba64 premultiplied() const
{
if (isOpaque())
return *this;
@@ -167,7 +127,7 @@ public:
#endif
}
- Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied() const
+ constexpr QRgba64 unpremultiplied() const
{
#if Q_PROCESSOR_WORDSIZE < 8
return unpremultiplied_32bit();
@@ -176,7 +136,7 @@ public:
#endif
}
- Q_DECL_CONSTEXPR operator quint64() const
+ constexpr operator quint64() const
{
return rgba;
}
@@ -188,11 +148,11 @@ public:
}
private:
- static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; }
+ static constexpr Q_ALWAYS_INLINE quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; }
- static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); }
- static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE quint8 div_257(quint16 x) { return div_257_floor(x + 128U); }
- Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_32bit() const
+ static constexpr Q_ALWAYS_INLINE quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); }
+ static constexpr Q_ALWAYS_INLINE quint8 div_257(quint16 x) { return div_257_floor(x + 128U); }
+ constexpr Q_ALWAYS_INLINE QRgba64 unpremultiplied_32bit() const
{
if (isOpaque() || isTransparent())
return *this;
@@ -202,7 +162,7 @@ private:
const quint16 b = quint16((blue() * 0xffff + a/2) / a);
return fromRgba64(r, g, b, quint16(a));
}
- Q_DECL_RELAXED_CONSTEXPR Q_ALWAYS_INLINE QRgba64 unpremultiplied_64bit() const
+ constexpr Q_ALWAYS_INLINE QRgba64 unpremultiplied_64bit() const
{
if (isOpaque() || isTransparent())
return *this;
@@ -217,36 +177,36 @@ private:
Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE);
-Q_DECL_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+constexpr inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
{
return QRgba64::fromRgba64(r, g, b, a);
}
-Q_DECL_CONSTEXPR inline QRgba64 qRgba64(quint64 c)
+constexpr inline QRgba64 qRgba64(quint64 c)
{
return QRgba64::fromRgba64(c);
}
-Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qPremultiply(QRgba64 c)
+constexpr inline QRgba64 qPremultiply(QRgba64 c)
{
return c.premultiplied();
}
-Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qUnpremultiply(QRgba64 c)
+constexpr inline QRgba64 qUnpremultiply(QRgba64 c)
{
return c.unpremultiplied();
}
-inline Q_DECL_CONSTEXPR uint qRed(QRgba64 rgb)
+inline constexpr uint qRed(QRgba64 rgb)
{ return rgb.red8(); }
-inline Q_DECL_CONSTEXPR uint qGreen(QRgba64 rgb)
+inline constexpr uint qGreen(QRgba64 rgb)
{ return rgb.green8(); }
-inline Q_DECL_CONSTEXPR uint qBlue(QRgba64 rgb)
+inline constexpr uint qBlue(QRgba64 rgb)
{ return rgb.blue8(); }
-inline Q_DECL_CONSTEXPR uint qAlpha(QRgba64 rgb)
+inline constexpr uint qAlpha(QRgba64 rgb)
{ return rgb.alpha8(); }
QT_END_NAMESPACE
diff --git a/src/gui/painting/qrgba64.qdoc b/src/gui/painting/qrgba64.qdoc
index 3ee8a355e6..fd78b539a3 100644
--- a/src/gui/painting/qrgba64.qdoc
+++ b/src/gui/painting/qrgba64.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QRgba64
diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h
index d145dbfbea..ae8b6fd8cb 100644
--- a/src/gui/painting/qrgba64_p.h
+++ b/src/gui/painting/qrgba64_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRGBA64_P_H
#define QRGBA64_P_H
@@ -64,40 +28,30 @@ inline QRgba64 combineAlpha256(QRgba64 rgba64, uint alpha256)
return QRgba64::fromRgba64(rgba64.red(), rgba64.green(), rgba64.blue(), (rgba64.alpha() * alpha256) >> 8);
}
-inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535)
-{
- return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535),
- qt_div_65535(rgba64.green() * alpha65535),
- qt_div_65535(rgba64.blue() * alpha65535),
- qt_div_65535(rgba64.alpha() * alpha65535));
-}
-
-#ifdef __SSE2__
-Q_ALWAYS_INLINE __m128i multiplyAlpha65535(__m128i rgba64, __m128i va)
+#if defined(__SSE2__)
+static inline __m128i Q_DECL_VECTORCALL multiplyAlpha65535(__m128i rgba64, __m128i va)
{
__m128i vs = rgba64;
vs = _mm_unpacklo_epi16(_mm_mullo_epi16(vs, va), _mm_mulhi_epu16(vs, va));
vs = _mm_add_epi32(vs, _mm_srli_epi32(vs, 16));
vs = _mm_add_epi32(vs, _mm_set1_epi32(0x8000));
vs = _mm_srai_epi32(vs, 16);
- vs = _mm_packs_epi32(vs, _mm_setzero_si128());
+ vs = _mm_packs_epi32(vs, vs);
return vs;
}
-Q_ALWAYS_INLINE __m128i multiplyAlpha65535(__m128i rgba64, uint alpha65535)
+static inline __m128i Q_DECL_VECTORCALL multiplyAlpha65535(__m128i rgba64, uint alpha65535)
{
const __m128i va = _mm_shufflelo_epi16(_mm_cvtsi32_si128(alpha65535), _MM_SHUFFLE(0, 0, 0, 0));
return multiplyAlpha65535(rgba64, va);
}
-#endif
-
-#if defined(__ARM_NEON__)
-Q_ALWAYS_INLINE uint16x4_t multiplyAlpha65535(uint16x4_t rgba64, uint16x4_t alpha65535)
+#elif defined(__ARM_NEON__)
+static inline uint16x4_t multiplyAlpha65535(uint16x4_t rgba64, uint16x4_t alpha65535)
{
uint32x4_t vs32 = vmull_u16(rgba64, alpha65535); // vs = vs * alpha
vs32 = vsraq_n_u32(vs32, vs32, 16); // vs = vs + (vs >> 16)
return vrshrn_n_u32(vs32, 16); // vs = (vs + 0x8000) >> 16
}
-Q_ALWAYS_INLINE uint16x4_t multiplyAlpha65535(uint16x4_t rgba64, uint alpha65535)
+static inline uint16x4_t multiplyAlpha65535(uint16x4_t rgba64, uint alpha65535)
{
uint32x4_t vs32 = vmull_n_u16(rgba64, alpha65535); // vs = vs * alpha
vs32 = vsraq_n_u32(vs32, vs32, 16); // vs = vs + (vs >> 16)
@@ -105,77 +59,144 @@ Q_ALWAYS_INLINE uint16x4_t multiplyAlpha65535(uint16x4_t rgba64, uint alpha65535
}
#endif
-template<typename T>
-inline T multiplyAlpha255(T rgba64, uint alpha255)
+static inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535)
{
+#if defined(__SSE2__)
+ const __m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgba64));
+ const __m128i vr = multiplyAlpha65535(v, alpha65535);
+ QRgba64 r;
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&r), vr);
+ return r;
+#elif defined(__ARM_NEON__)
+ const uint16x4_t v = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&rgba64)));
+ const uint16x4_t vr = multiplyAlpha65535(v, alpha65535);
+ QRgba64 r;
+ vst1_u64(reinterpret_cast<uint64_t *>(&r), vreinterpret_u64_u16(vr));
+ return r;
+#else
+ return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535),
+ qt_div_65535(rgba64.green() * alpha65535),
+ qt_div_65535(rgba64.blue() * alpha65535),
+ qt_div_65535(rgba64.alpha() * alpha65535));
+#endif
+}
+
#if defined(__SSE2__) || defined(__ARM_NEON__)
+template<typename T>
+static inline T Q_DECL_VECTORCALL multiplyAlpha255(T rgba64, uint alpha255)
+{
return multiplyAlpha65535(rgba64, alpha255 * 257);
+}
#else
+template<typename T>
+static inline T multiplyAlpha255(T rgba64, uint alpha255)
+{
return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255),
qt_div_255(rgba64.green() * alpha255),
qt_div_255(rgba64.blue() * alpha255),
qt_div_255(rgba64.alpha() * alpha255));
-#endif
-}
-
-inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2)
-{
- return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2));
}
+#endif
#if defined __SSE2__
-Q_ALWAYS_INLINE __m128i interpolate255(__m128i x, uint alpha1, __m128i y, uint alpha2)
+static inline __m128i Q_DECL_VECTORCALL interpolate255(__m128i x, uint alpha1, __m128i y, uint alpha2)
{
- return _mm_add_epi32(multiplyAlpha255(x, alpha1), multiplyAlpha255(y, alpha2));
+ return _mm_add_epi16(multiplyAlpha255(x, alpha1), multiplyAlpha255(y, alpha2));
}
#endif
#if defined __ARM_NEON__
-Q_ALWAYS_INLINE uint16x4_t interpolate255(uint16x4_t x, uint alpha1, uint16x4_t y, uint alpha2)
+inline uint16x4_t interpolate255(uint16x4_t x, uint alpha1, uint16x4_t y, uint alpha2)
{
return vadd_u16(multiplyAlpha255(x, alpha1), multiplyAlpha255(y, alpha2));
}
#endif
-inline QRgba64 interpolate65535(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2)
+static inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2)
{
- return QRgba64::fromRgba64(multiplyAlpha65535(x, alpha1) + multiplyAlpha65535(y, alpha2));
+#if defined(__SSE2__)
+ const __m128i vx = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&x));
+ const __m128i vy = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&y));
+ const __m128i vr = interpolate255(vx, alpha1, vy, alpha2);
+ QRgba64 r;
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&r), vr);
+ return r;
+#elif defined(__ARM_NEON__)
+ const uint16x4_t vx = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&x)));
+ const uint16x4_t vy = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&y)));
+ const uint16x4_t vr = interpolate255(vx, alpha1, vy, alpha2);
+ QRgba64 r;
+ vst1_u64(reinterpret_cast<uint64_t *>(&r), vreinterpret_u64_u16(vr));
+ return r;
+#else
+ return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2));
+#endif
}
#if defined __SSE2__
-Q_ALWAYS_INLINE __m128i interpolate65535(__m128i x, uint alpha1, __m128i y, uint alpha2)
+static inline __m128i Q_DECL_VECTORCALL interpolate65535(__m128i x, uint alpha1, __m128i y, uint alpha2)
{
- return _mm_add_epi32(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
+ return _mm_add_epi16(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
}
-// alpha2 below is const-ref because otherwise MSVC2015 complains that it can't 16-byte align the argument.
-Q_ALWAYS_INLINE __m128i interpolate65535(__m128i x, __m128i alpha1, __m128i y, const __m128i &alpha2)
+
+static inline __m128i Q_DECL_VECTORCALL interpolate65535(__m128i x, __m128i alpha1, __m128i y, __m128i alpha2)
{
- return _mm_add_epi32(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
+ return _mm_add_epi16(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
}
#endif
#if defined __ARM_NEON__
-Q_ALWAYS_INLINE uint16x4_t interpolate65535(uint16x4_t x, uint alpha1, uint16x4_t y, uint alpha2)
+inline uint16x4_t interpolate65535(uint16x4_t x, uint alpha1, uint16x4_t y, uint alpha2)
{
return vadd_u16(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
}
-Q_ALWAYS_INLINE uint16x4_t interpolate65535(uint16x4_t x, uint16x4_t alpha1, uint16x4_t y, uint16x4_t alpha2)
+inline uint16x4_t interpolate65535(uint16x4_t x, uint16x4_t alpha1, uint16x4_t y, uint16x4_t alpha2)
{
return vadd_u16(multiplyAlpha65535(x, alpha1), multiplyAlpha65535(y, alpha2));
}
#endif
-inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b)
+static inline QRgba64 interpolate65535(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2)
{
+#if defined(__SSE2__)
+ const __m128i vx = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&x));
+ const __m128i vy = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&y));
+ const __m128i vr = interpolate65535(vx, alpha1, vy, alpha2);
+ QRgba64 r;
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&r), vr);
+ return r;
+#elif defined(__ARM_NEON__)
+ const uint16x4_t vx = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&x)));
+ const uint16x4_t vy = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&y)));
+ const uint16x4_t vr = interpolate65535(vx, alpha1, vy, alpha2);
+ QRgba64 r;
+ vst1_u64(reinterpret_cast<uint64_t *>(&r), vreinterpret_u64_u16(vr));
+ return r;
+#else
+ return QRgba64::fromRgba64(multiplyAlpha65535(x, alpha1) + multiplyAlpha65535(y, alpha2));
+#endif
+}
+
+static inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b)
+{
+#if defined(__SSE2__)
+ const __m128i va = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&a));
+ const __m128i vb = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&b));
+ const __m128i vr = _mm_adds_epu16(va, vb);
+ QRgba64 r;
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&r), vr);
+ return r;
+#else
return QRgba64::fromRgba64(qMin(a.red() + b.red(), 65535),
qMin(a.green() + b.green(), 65535),
qMin(a.blue() + b.blue(), 65535),
qMin(a.alpha() + b.alpha(), 65535));
+#endif
}
#if QT_COMPILER_SUPPORTS_HERE(SSE2)
QT_FUNCTION_TARGET(SSE2)
-Q_ALWAYS_INLINE uint toArgb32(__m128i v)
+static inline uint Q_DECL_VECTORCALL toArgb32(__m128i v)
{
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
v = _mm_add_epi32(v, _mm_set1_epi32(128));
@@ -186,7 +207,7 @@ Q_ALWAYS_INLINE uint toArgb32(__m128i v)
return _mm_cvtsi128_si32(v);
}
#elif defined __ARM_NEON__
-Q_ALWAYS_INLINE uint toArgb32(uint16x4_t v)
+static inline uint toArgb32(uint16x4_t v)
{
v = vsub_u16(v, vrshr_n_u16(v, 8));
v = vrshr_n_u16(v, 8);
@@ -195,10 +216,10 @@ Q_ALWAYS_INLINE uint toArgb32(uint16x4_t v)
}
#endif
-inline uint toArgb32(QRgba64 rgba64)
+static inline uint toArgb32(QRgba64 rgba64)
{
#if defined __SSE2__
- __m128i v = _mm_loadl_epi64((const __m128i *)&rgba64);
+ __m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgba64));
v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3, 0, 1, 2));
return toArgb32(v);
#elif defined __ARM_NEON__
@@ -215,10 +236,10 @@ inline uint toArgb32(QRgba64 rgba64)
#endif
}
-inline uint toRgba8888(QRgba64 rgba64)
+static inline uint toRgba8888(QRgba64 rgba64)
{
#if defined __SSE2__
- __m128i v = _mm_loadl_epi64((const __m128i *)&rgba64);
+ __m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgba64));
return toArgb32(v);
#elif defined __ARM_NEON__
uint16x4_t v = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&rgba64)));
@@ -228,12 +249,12 @@ inline uint toRgba8888(QRgba64 rgba64)
#endif
}
-inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha)
+static inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha)
{
QRgba64 blend;
#if defined(__SSE2__)
- __m128i vd = _mm_loadl_epi64((const __m128i *)&d);
- __m128i vs = _mm_loadl_epi64((const __m128i *)&s);
+ __m128i vd = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&d));
+ __m128i vs = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&s));
__m128i va = _mm_cvtsi32_si128(rgbAlpha);
va = _mm_unpacklo_epi8(va, va);
va = _mm_shufflelo_epi16(va, _MM_SHUFFLE(3, 0, 1, 2));
@@ -245,9 +266,9 @@ inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha)
vd = _mm_add_epi32(vd, _mm_srli_epi32(vd, 16));
vd = _mm_add_epi32(vd, _mm_set1_epi32(0x8000));
vd = _mm_srai_epi32(vd, 16);
- vd = _mm_packs_epi32(vd, _mm_setzero_si128());
+ vd = _mm_packs_epi32(vd, vd);
- _mm_storel_epi64((__m128i *)&blend, vd);
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&blend), vd);
#elif defined(__ARM_NEON__)
uint16x4_t vd = vreinterpret_u16_u64(vmov_n_u64(d));
uint16x4_t vs = vreinterpret_u16_u64(vmov_n_u64(s));
@@ -274,21 +295,39 @@ inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha)
return blend;
}
-static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src)
+static inline void blend_pixel(QRgba64 &dst, QRgba64 src)
{
if (src.isOpaque())
dst = src;
- else if (!src.isTransparent())
+ else if (!src.isTransparent()) {
+#if defined(__SSE2__)
+ const __m128i vd = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&dst));
+ const __m128i vs = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&src));
+ const __m128i via = _mm_xor_si128(_mm_set1_epi16(-1), _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3)));
+ const __m128i vr = _mm_add_epi16(vs, multiplyAlpha65535(vd, via));
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&dst), vr);
+#else
dst = src + multiplyAlpha65535(dst, 65535 - src.alpha());
+#endif
+ }
}
-static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha)
+static inline void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha)
{
if (const_alpha == 255)
return blend_pixel(dst, src);
if (!src.isTransparent()) {
+#if defined(__SSE2__)
+ const __m128i vd = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&dst));
+ __m128i vs = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&src));
+ vs = multiplyAlpha255(vs, const_alpha);
+ const __m128i via = _mm_xor_si128(_mm_set1_epi16(-1), _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3)));
+ const __m128i vr = _mm_add_epi16(vs, multiplyAlpha65535(vd, via));
+ _mm_storel_epi64(reinterpret_cast<__m128i *>(&dst), vr);
+#else
src = multiplyAlpha255(src, const_alpha);
dst = src + multiplyAlpha65535(dst, 65535 - src.alpha());
+#endif
}
}
diff --git a/src/gui/painting/qrgbafloat.h b/src/gui/painting/qrgbafloat.h
new file mode 100644
index 0000000000..da74328f71
--- /dev/null
+++ b/src/gui/painting/qrgbafloat.h
@@ -0,0 +1,126 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRGBAFLOAT_H
+#define QRGBAFLOAT_H
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qfloat16.h>
+
+#include <algorithm>
+#include <cmath>
+#include <type_traits>
+
+QT_BEGIN_NAMESPACE
+
+template<typename F>
+class alignas(sizeof(F) * 4) QRgbaFloat
+{
+ static_assert(std::is_same<F, qfloat16>::value || std::is_same<F, float>::value);
+public:
+ using Type = F;
+#if defined(__AVX512FP16__) && QFLOAT16_IS_NATIVE
+ // AVX512FP16 has multiplication instructions
+ using FastType = F;
+#else
+ // use FP32 for multiplications
+ using FastType = float;
+#endif
+ F r;
+ F g;
+ F b;
+ F a;
+
+ static constexpr
+ QRgbaFloat fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
+ {
+ constexpr FastType scale = FastType(1.0f / 65535.0f);
+ return QRgbaFloat{
+ F(red * scale),
+ F(green * scale),
+ F(blue * scale),
+ F(alpha * scale) };
+ }
+
+ static constexpr
+ QRgbaFloat fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+ {
+ constexpr FastType scale = FastType(1.0f / 255.0f);
+ return QRgbaFloat{
+ F(red * scale),
+ F(green * scale),
+ F(blue * scale),
+ F(alpha * scale) };
+ }
+ static constexpr
+ QRgbaFloat fromArgb32(uint rgb)
+ {
+ return fromRgba(quint8(rgb >> 16), quint8(rgb >> 8), quint8(rgb), quint8(rgb >> 24));
+ }
+
+ constexpr bool isOpaque() const { return a >= FastType(1.0f); }
+ constexpr bool isTransparent() const { return a <= FastType(0.0f); }
+
+ constexpr float red() const { return r; }
+ constexpr float green() const { return g; }
+ constexpr float blue() const { return b; }
+ constexpr float alpha() const { return a; }
+ void setRed(float _red) { r = F(_red); }
+ void setGreen(float _green) { g = F(_green); }
+ void setBlue(float _blue) { b = F(_blue); }
+ void setAlpha(float _alpha) { a = F(_alpha); }
+
+ constexpr float redNormalized() const { return clamp01(r); }
+ constexpr float greenNormalized() const { return clamp01(g); }
+ constexpr float blueNormalized() const { return clamp01(b); }
+ constexpr float alphaNormalized() const { return clamp01(a); }
+
+ constexpr quint8 red8() const { return qRound(redNormalized() * FastType(255.0f)); }
+ constexpr quint8 green8() const { return qRound(greenNormalized() * FastType(255.0f)); }
+ constexpr quint8 blue8() const { return qRound(blueNormalized() * FastType(255.0f)); }
+ constexpr quint8 alpha8() const { return qRound(alphaNormalized() * FastType(255.0f)); }
+ constexpr uint toArgb32() const
+ {
+ return uint((alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8());
+ }
+
+ constexpr quint16 red16() const { return qRound(redNormalized() * FastType(65535.0f)); }
+ constexpr quint16 green16() const { return qRound(greenNormalized() * FastType(65535.0f)); }
+ constexpr quint16 blue16() const { return qRound(blueNormalized() * FastType(65535.0f)); }
+ constexpr quint16 alpha16() const { return qRound(alphaNormalized() * FastType(65535.0f)); }
+
+ constexpr Q_ALWAYS_INLINE QRgbaFloat premultiplied() const
+ {
+ return QRgbaFloat{r * a, g * a, b * a, a};
+ }
+ constexpr Q_ALWAYS_INLINE QRgbaFloat unpremultiplied() const
+ {
+ if (a <= F{0.0f})
+ return QRgbaFloat{}; // default-initialization: zeroes
+ if (a >= F{1.0f})
+ return *this;
+ const FastType ia = 1.0f / a;
+ return QRgbaFloat{F(r * ia), F(g * ia), F(b * ia), F(a)};
+ }
+ constexpr bool operator==(QRgbaFloat f) const
+ {
+ return r == f.r && g == f.g && b == f.b && a == f.a;
+ }
+ constexpr bool operator!=(QRgbaFloat f) const
+ {
+ return !(*this == f);
+ }
+
+private:
+ constexpr static FastType clamp01(Type f)
+ {
+ return std::clamp(FastType(f), FastType(0.0f), FastType(1.0f));
+ }
+};
+
+typedef QRgbaFloat<qfloat16> QRgbaFloat16;
+typedef QRgbaFloat<float> QRgbaFloat32;
+
+QT_END_NAMESPACE
+
+#endif // QRGBAFLOAT_H
diff --git a/src/gui/painting/qrgbafloat.qdoc b/src/gui/painting/qrgbafloat.qdoc
new file mode 100644
index 0000000000..3ec0d209f4
--- /dev/null
+++ b/src/gui/painting/qrgbafloat.qdoc
@@ -0,0 +1,241 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \class QRgbaFloat
+ \brief The QRgbaFloat struct contains a four part RGBA floating-point color.
+ \since 6.2
+
+ \ingroup painting
+ \inmodule QtGui
+
+ \sa QRgb, QRgba64, QColor
+*/
+
+/*!
+ \typealias QRgbaFloat::FastType
+
+ Alias for \e float.
+*/
+
+/*!
+ \typedef QRgbaFloat16
+ \relates QRgbaFloat
+
+ A 64-bit data-structure containing four 16-bit floating point color channels: Red, green, blue and alpha.
+*/
+
+/*!
+ \typedef QRgbaFloat32
+ \relates QRgbaFloat
+
+ A 128-bit data-structure containing four 32-bit floating point color channels: Red, green, blue and alpha.
+*/
+
+/*!
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
+
+ Constructs a QRgbaFloat value from the four 16-bit integer color channels \a red, \a green, \a blue and \a alpha.
+
+ \sa fromRgba()
+*/
+
+/*!
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+
+ Constructs a QRgbaFloat value from the four 8-bit color channels \a red, \a green, \a blue and \a alpha.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromArgb32(uint rgb)
+
+ Constructs a QRgbaFloat value from the 32bit ARGB value \a rgb.
+
+ \sa fromRgba(), toArgb32()
+*/
+
+/*!
+ \fn template<typename F> bool QRgbaFloat<F>::isOpaque() const
+
+ Returns whether the color is fully opaque.
+
+ \sa isTransparent(), alpha()
+*/
+
+/*!
+ \fn template<typename F> bool QRgbaFloat<F>::isTransparent() const
+
+ Returns whether the color is fully transparent.
+
+ \sa isOpaque(), alpha()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::red() const
+
+ Returns the red color component.
+
+ \sa setRed()
+*/
+
+/*!
+ \fn template<typename F> void QRgbaFloat<F>::setRed(float red)
+
+ Sets the red color component of this color to \a red.
+
+ \sa red()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::green() const
+
+ Returns the green color component.
+
+ \sa setGreen()
+*/
+
+/*!
+ \fn template<typename F> void QRgbaFloat<F>::setGreen(float green)
+
+ Sets the green color component of this color to \a green.
+
+ \sa green()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::blue() const
+
+ Returns the blue color component.
+
+ \sa setBlue()
+*/
+
+/*!
+ \fn template<typename F> void QRgbaFloat<F>::setBlue(float blue)
+
+ Sets the blue color component of this color to \a blue.
+
+ \sa blue()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::alpha() const
+
+ Returns the alpha channel.
+
+ \sa setAlpha()
+*/
+
+/*!
+ \fn template<typename F> void QRgbaFloat<F>::setAlpha(float alpha)
+
+ Sets the alpha of this color to \a alpha.
+
+ \sa alpha()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::redNormalized() const
+
+ Returns the red color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setRed()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::greenNormalized() const
+
+ Returns the green color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setGreen()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::blueNormalized() const
+
+ Returns the blue color component normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa setBlue()
+*/
+
+/*!
+ \fn template<typename F> float QRgbaFloat<F>::alphaNormalized() const
+
+ Returns the alpha channel normalized to values between \c 0.0f and \c 1.0f.
+
+ \sa alpha()
+*/
+
+/*!
+ \fn template<typename F> quint8 QRgbaFloat<F>::red8() const
+
+ Returns the red color component as an 8-bit.
+*/
+
+/*!
+ \fn template<typename F> quint8 QRgbaFloat<F>::green8() const
+
+ Returns the green color component as an 8-bit.
+*/
+
+/*!
+ \fn template<typename F> quint8 QRgbaFloat<F>::blue8() const
+
+ Returns the blue color component as an 8-bit.
+*/
+
+/*!
+ \fn template<typename F> quint8 QRgbaFloat<F>::alpha8() const
+
+ Returns the alpha channel as an 8-bit.
+*/
+
+/*!
+ \fn template<typename F> uint QRgbaFloat<F>::toArgb32() const
+
+ Returns the color as a 32-bit ARGB value.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn template<typename F> quint16 QRgbaFloat<F>::red16() const
+
+ Returns the red color component as a 16-bit integer.
+*/
+
+/*!
+ \fn template<typename F> quint16 QRgbaFloat<F>::green16() const
+
+ Returns the green color component as a 16-bit integer.
+*/
+
+/*!
+ \fn template<typename F> quint16 QRgbaFloat<F>::blue16() const
+
+ Returns the blue color component as a 16-bit integer.
+*/
+
+/*!
+ \fn template<typename F> quint16 QRgbaFloat<F>::alpha16() const
+
+ Returns the alpha channel as a 16-bit integer.
+*/
+
+/*!
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::premultiplied() const
+
+ Returns the color with the alpha premultiplied.
+
+ \sa unpremultiplied()
+*/
+
+/*!
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::unpremultiplied() const
+
+ Returns the color with the alpha unpremultiplied.
+
+ \sa premultiplied()
+*/
diff --git a/src/gui/painting/qrhibackingstore.cpp b/src/gui/painting/qrhibackingstore.cpp
new file mode 100644
index 0000000000..586dfb44a4
--- /dev/null
+++ b/src/gui/painting/qrhibackingstore.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrhibackingstore_p.h"
+#include <private/qimage_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QRhiBackingStore::QRhiBackingStore(QWindow *window)
+ : QRasterBackingStore(window)
+{
+}
+
+QRhiBackingStore::~QRhiBackingStore()
+{
+}
+
+void QRhiBackingStore::flush(QWindow *flushedWindow, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+ if (flushedWindow->surfaceType() != window()->surfaceType()) {
+ qWarning() << "Cannot flush child window" << flushedWindow
+ << "with surface type" << flushedWindow->surfaceType() << ";"
+ << "Must match" << window()->surfaceType() << "of" << window();
+
+ // FIXME: Support different surface types by not tying the
+ // RHI config to the backing store itself (per window config).
+ return;
+ }
+
+ if (!rhi()) {
+ QPlatformBackingStoreRhiConfig rhiConfig;
+ switch (window()->surfaceType()) {
+ case QSurface::OpenGLSurface:
+ rhiConfig.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
+ break;
+ case QSurface::MetalSurface:
+ rhiConfig.setApi(QPlatformBackingStoreRhiConfig::Metal);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ rhiConfig.setEnabled(true);
+ setRhiConfig(rhiConfig);
+ }
+
+ static QPlatformTextureList emptyTextureList;
+ bool translucentBackground = m_image.hasAlphaChannel();
+ rhiFlush(flushedWindow, flushedWindow->devicePixelRatio(),
+ region, offset, &emptyTextureList, translucentBackground);
+}
+
+QImage::Format QRhiBackingStore::format() const
+{
+ QImage::Format fmt = QRasterBackingStore::format();
+
+ // With render-to-texture widgets and QRhi-based flushing the backingstore
+ // image must have an alpha channel. Hence upgrading the format. Matches
+ // what other platforms (Windows, xcb) do.
+ if (QImage::toPixelFormat(fmt).alphaUsage() != QPixelFormat::UsesAlpha)
+ fmt = qt_maybeDataCompatibleAlphaVersion(fmt);
+
+ return fmt;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qrhibackingstore_p.h b/src/gui/painting/qrhibackingstore_p.h
new file mode 100644
index 0000000000..f222db860f
--- /dev/null
+++ b/src/gui/painting/qrhibackingstore_p.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHIBACKINGSTORE_H
+#define QRHIBACKINGSTORE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qrasterbackingstore_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QRhiBackingStore : public QRasterBackingStore
+{
+public:
+ QRhiBackingStore(QWindow *window);
+ ~QRhiBackingStore();
+
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
+ QImage::Format format() const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QRHIBACKINGSTORE_H
diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp
index 22302f9790..79799ca2ec 100644
--- a/src/gui/painting/qstroker.cpp
+++ b/src/gui/painting/qstroker.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qstroker_p.h"
#include "private/qbezier_p.h"
@@ -295,7 +259,7 @@ void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const Q
/*!
Convenience function for stroking a polygon of the \a pointCount
first points in \a points. If \a implicit_close is set to true a
- line is implictly drawn between the first and last point in the
+ line is implicitly drawn between the first and last point in the
polygon. Typically true for polygons and false for polylines.
The \a matrix is used to transform the points before they enter the
@@ -1028,13 +992,13 @@ QDashStroker::~QDashStroker()
{
}
-QVector<qfixed> QDashStroker::patternForStyle(Qt::PenStyle style)
+QList<qfixed> QDashStroker::patternForStyle(Qt::PenStyle style)
{
const qfixed space = 2;
const qfixed dot = 1;
const qfixed dash = 4;
- QVector<qfixed> pattern;
+ QList<qfixed> pattern;
switch (style) {
case Qt::DashLine:
@@ -1133,7 +1097,9 @@ void QDashStroker::processCurrentSubpath()
qreal doffset = m_dashOffset * m_stroke_width;
// make sure doffset is in range [0..sumLength)
- doffset -= qFloor(doffset * invSumLength) * sumLength;
+ doffset = std::fmod(doffset, sumLength);
+ if (doffset < 0)
+ doffset += sumLength;
while (doffset >= dashes[idash]) {
doffset -= dashes[idash];
@@ -1179,32 +1145,42 @@ void QDashStroker::processCurrentSubpath()
bool done = pos >= estop;
- if (clipping) {
- // Check if the entire line can be clipped away.
- if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
- // Cut away full dash sequences.
- elen -= qFloor(elen * invSumLength) * sumLength;
- // Update dash offset.
- while (!done) {
- qreal dpos = pos + dashes[idash] - doffset - estart;
-
- Q_ASSERT(dpos >= 0);
-
- if (dpos > elen) { // dash extends this line
- doffset = dashes[idash] - (dpos - elen); // subtract the part already used
- pos = estop; // move pos to next path element
- done = true;
- } else { // Dash is on this line
- pos = dpos + estart;
- done = pos >= estop;
- if (++idash >= dashCount)
- idash = 0;
- doffset = 0; // full segment so no offset on next.
- }
+ // Check if the entire line should be clipped away or simplified
+ bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
+ bool skipDashing = elen * invSumLength > repetitionLimit();
+ int maxDashes = dashCount;
+ if (skipDashing || clipIt) {
+ // Cut away full dash sequences.
+ elen -= std::floor(elen * invSumLength) * sumLength;
+ // Update dash offset.
+ while (!done) {
+ qreal dpos = pos + dashes[idash] - doffset - estart;
+
+ Q_ASSERT(dpos >= 0);
+
+ if (dpos > elen) { // dash extends this line
+ doffset = dashes[idash] - (dpos - elen); // subtract the part already used
+ pos = estop; // move pos to next path element
+ done = true;
+ } else { // Dash is on this line
+ pos = --maxDashes > 0 ? dpos + estart : estop;
+ done = pos >= estop;
+ if (++idash >= dashCount)
+ idash = 0;
+ doffset = 0; // full segment so no offset on next.
}
+ }
+ if (clipIt) {
hasMoveTo = false;
- move_to_pos = e;
+ } else {
+ // skip costly dashing, just draw solid line
+ if (!hasMoveTo) {
+ emitMoveTo(move_to_pos.x, move_to_pos.y);
+ hasMoveTo = true;
+ }
+ emitLineTo(e.x, e.y);
}
+ move_to_pos = e;
}
// Dash away...
diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h
index 0a9f55f222..2519bbadc2 100644
--- a/src/gui/painting/qstroker_p.h
+++ b/src/gui/painting/qstroker_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSTROKER_P_H
#define QSTROKER_P_H
@@ -209,7 +173,11 @@ public:
QStroker();
~QStroker();
- void setStrokeWidth(qfixed width) { m_strokeWidth = width; m_curveThreshold = qt_real_to_fixed(qBound(0.025, 1.0/width, 0.25)); }
+ void setStrokeWidth(qfixed width)
+ {
+ m_strokeWidth = width;
+ m_curveThreshold = qt_real_to_fixed(qBound(0.00025, 1.0 / qt_fixed_to_real(width), 0.25));
+ }
qfixed strokeWidth() const { return m_strokeWidth; }
void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); }
@@ -224,7 +192,7 @@ public:
qfixed miterLimit() const { return m_miterLimit; }
void setForceOpen(bool state) { m_forceOpen = state; }
- bool forceOpen() { return m_forceOpen; }
+ bool forceOpen() const { return m_forceOpen; }
void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join);
inline void emitMoveTo(qfixed x, qfixed y);
@@ -264,6 +232,7 @@ public:
QStroker *stroker() const { return m_stroker; }
static QList<qfixed> patternForStyle(Qt::PenStyle style);
+ static int repetitionLimit() { return 10000; }
void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
QList<qfixed> dashPattern() const { return m_dashPattern; }
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index e2326a56c1..33ed2fd5c7 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -4,13 +4,13 @@
"Name": "Anti-aliasing rasterizer from FreeType 2",
"QDocModule": "qtgui",
"QtUsage": "Used in Qt GUI.",
- "Path": "qgrayraster.c",
+ "Files": "qgrayraster.c",
"Description": "FreeType is a freely available software library to render fonts.",
"Homepage": "http://www.freetype.org",
"License": "Freetype Project License or GNU General Public License v2.0 only",
- "LicenseId": "FTL or GPL-2.0",
- "LicenseFile": "../../3rdparty/freetype/docs/LICENSE.TXT",
+ "LicenseId": "FTL OR GPL-2.0-only",
+ "LicenseFile": "../../3rdparty/freetype/LICENSE.txt",
"Copyright": "Copyright 2000-2016 by David Turner, Robert Wilhelm, and Werner Lemberg."
},
{
@@ -24,9 +24,9 @@
"LicenseId": "BSD-2-Clause AND Imlib2",
"License": "BSD 2-clause \"Simplified\" License and Imlib2 License",
"LicenseFile": "QIMAGETRANSFORM_LICENSE.txt",
- "Copyright": "Copyright (C) 2004, 2005 Daniel M. Duley.
- (C) Carsten Haitzler and various contributors.
- (C) Willem Monsuwe <willem@stack.nl>"
+ "Copyright": ["Copyright (C) 2004, 2005 Daniel M. Duley.",
+ "(C) Carsten Haitzler and various contributors.",
+ "(C) Willem Monsuwe <willem@stack.nl>"]
},
{
"Id": "xserverhelper",
@@ -40,7 +40,7 @@
"License": "X11 License and Historical Permission Notice and Disclaimer",
"LicenseId": "X11 AND HPND",
"LicenseFile": "XCONSORTIUM_LICENSE.txt",
- "Copyright": "Copyright (c) 1987, 1988 X Consortium
-Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."
+ "Copyright": ["Copyright (c) 1987, 1988 X Consortium",
+ "Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."]
}
]
diff --git a/src/gui/painting/qt_mips_asm_dsp_p.h b/src/gui/painting/qt_mips_asm_dsp_p.h
index 172910ea1c..6b33285f32 100644
--- a/src/gui/painting/qt_mips_asm_dsp_p.h
+++ b/src/gui/painting/qt_mips_asm_dsp_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2013 Imagination Technologies Limited, www.imgtec.com
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QT_MIPS_ASM_DSP_H
#define QT_MIPS_ASM_DSP_H
@@ -55,7 +19,7 @@
#pragma qt_sync_stop_processing
#endif
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
#define zero $0
#define AT $1
#define v0 $2
@@ -277,7 +241,7 @@ LEAF_MIPS32R2(symbol) \
/*
* Saves set of registers on stack. Maximum number of registers that
- * can be saved on stack is limitted to 14 (a0-a3, v0-v1 and s0-s7).
+ * can be saved on stack is limited to 14 (a0-a3, v0-v1 and s0-s7).
* Stack offset is number of bytes that are added to stack pointer (sp)
* before registers are pushed in order to provide enough space on stack
* (offset must be multiple of 4, and must be big enough, as described by
@@ -352,7 +316,7 @@ LEAF_MIPS32R2(symbol) \
/*
* Restores set of registers from stack. Maximum number of registers that
- * can be restored from stack is limitted to 14 (a0-a3, v0-v1 and s0-s7).
+ * can be restored from stack is limited to 14 (a0-a3, v0-v1 and s0-s7).
* Stack offset is number of bytes that are added to stack pointer (sp)
* after registers are restored (offset must be multiple of 4, and must
* be big enough, as described by CHECK_STACK_OFFSET macro). This macro is
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 3728060caf..70d70e342a 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <qmath.h>
@@ -64,7 +28,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
QImage images[NumSubpixelPositions];
int numImages = 0;
for (int i = 0; i < NumSubpixelPositions; ++i) {
- QImage img = textureMapForGlyph(glyph, QFixed::fromReal(i / 12.0));
+ QImage img = textureMapForGlyph(glyph, QFixedPoint(QFixed::fromReal(i / 12.0), 0));
if (numImages == 0) {
QPainterPath path;
@@ -92,11 +56,15 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
return numImages;
}
-bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions)
+bool QTextureGlyphCache::populate(QFontEngine *fontEngine,
+ qsizetype numGlyphs,
+ const glyph_t *glyphs,
+ const QFixedPoint *positions,
+ QPainter::RenderHints renderHints,
+ bool includeGlyphCacheScale)
{
#ifdef CACHE_DEBUG
- printf("Populating with %d glyphs\n", numGlyphs);
+ printf("Populating with %lld glyphs\n", static_cast<long long>(numGlyphs));
qDebug() << " -> current transformation: " << m_transform;
#endif
@@ -105,11 +73,13 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
const int paddingDoubled = padding * 2;
bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
+ bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
+ && (renderHints & QPainter::VerticalSubpixelPositioning) != 0;
if (fontEngine->m_subPixelPositionCount == 0) {
if (!supportsSubPixelPositions) {
fontEngine->m_subPixelPositionCount = 1;
} else {
- int i = 0;
+ qsizetype i = 0;
while (fontEngine->m_subPixelPositionCount == 0 && i < numGlyphs)
fontEngine->m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
}
@@ -120,17 +90,26 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
m_cy = padding;
}
+ qreal glyphCacheScaleX = transform().m11();
+ qreal glyphCacheScaleY = transform().m22();
+
QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
int rowHeight = 0;
// check each glyph for its metrics and get the required rowHeight.
- for (int i=0; i < numGlyphs; ++i) {
+ for (qsizetype i = 0; i < numGlyphs; ++i) {
const glyph_t glyph = glyphs[i];
- QFixed subPixelPosition;
+ QFixedPoint subPixelPosition;
if (supportsSubPixelPositions) {
- QFixed x = positions != nullptr ? positions[i].x : QFixed();
- subPixelPosition = fontEngine->subPixelPositionForX(x);
+ QFixedPoint pos = positions != nullptr ? positions[i] : QFixedPoint();
+ if (includeGlyphCacheScale) {
+ pos = QFixedPoint(QFixed::fromReal(pos.x.toReal() * glyphCacheScaleX),
+ QFixed::fromReal(pos.y.toReal() * glyphCacheScaleY));
+ }
+ subPixelPosition = fontEngine->subPixelPositionFor(pos);
+ if (!verticalSubPixelPositions)
+ subPixelPosition.y = 0;
}
if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
@@ -263,7 +242,7 @@ void QTextureGlyphCache::fillInPendingGlyphs()
m_pendingGlyphs.clear();
}
-QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const
+QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition) const
{
switch (m_format) {
case QFontEngine::Format_A32:
@@ -317,7 +296,9 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
m_image.fill(0);
}
-void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition)
+void QImageTextureGlyphCache::fillTexture(const Coord &c,
+ glyph_t g,
+ const QFixedPoint &subPixelPosition)
{
QImage mask = textureMapForGlyph(g, subPixelPosition);
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index 2f99f44741..c0218b3ace 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTEXTUREGLYPHCACHE_P_H
#define QTEXTUREGLYPHCACHE_P_H
@@ -83,7 +47,8 @@ public:
struct GlyphAndSubPixelPosition
{
- GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
+ GlyphAndSubPixelPosition(glyph_t g, const QFixedPoint &spp)
+ : glyph(g), subPixelPosition(spp) {}
bool operator==(const GlyphAndSubPixelPosition &other) const
{
@@ -91,7 +56,7 @@ public:
}
glyph_t glyph;
- QFixed subPixelPosition;
+ QFixedPoint subPixelPosition;
};
struct Coord {
@@ -109,9 +74,13 @@ public:
}
};
- bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions);
- bool hasPendingGlyphs() const { return !m_pendingGlyphs.isEmpty(); };
+ bool populate(QFontEngine *fontEngine,
+ qsizetype numGlyphs,
+ const glyph_t *glyphs,
+ const QFixedPoint *positions,
+ QPainter::RenderHints renderHints = QPainter::RenderHints(),
+ bool includeGlyphCacheScale = false);
+ bool hasPendingGlyphs() const { return !m_pendingGlyphs.isEmpty(); }
void fillInPendingGlyphs();
virtual void createTextureData(int width, int height) = 0;
@@ -119,7 +88,9 @@ public:
virtual int glyphPadding() const { return 0; }
virtual void beginFillTexture() { }
- virtual void fillTexture(const Coord &coord, glyph_t glyph, QFixed subPixelPosition) = 0;
+ virtual void fillTexture(const Coord &coord,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition) = 0;
virtual void endFillTexture() { }
inline void createCache(int width, int height) {
@@ -141,7 +112,7 @@ public:
virtual int maxTextureWidth() const { return QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; }
virtual int maxTextureHeight() const { return -1; }
- QImage textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const;
+ QImage textureMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition) const;
protected:
int calculateSubPixelPositionCount(glyph_t) const;
@@ -156,9 +127,12 @@ protected:
int m_currentRowHeight; // Height of last row
};
-inline size_t qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g)
+inline size_t qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g, size_t seed = 0)
{
- return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();
+ return qHashMulti(seed,
+ g.glyph,
+ g.subPixelPosition.x.value(),
+ g.subPixelPosition.y.value());
}
@@ -171,7 +145,9 @@ public:
virtual void createTextureData(int width, int height) override;
virtual void resizeTextureData(int width, int height) override;
- virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) override;
+ virtual void fillTexture(const Coord &c,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition) override;
inline const QImage &image() const { return m_image; }
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 8f8a675fc9..df57d2c190 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtransform.h"
#include "qdatastream.h"
@@ -45,7 +9,7 @@
#include "qpainterpath.h"
#include "qpainterpath_p.h"
#include "qvariant.h"
-#include <qmath.h>
+#include "qmath_p.h"
#include <qnumeric.h>
#include <private/qbezier_p.h>
@@ -90,7 +54,7 @@ static void nanWarning(const char *func)
if (t == TxProject) { \
qreal w = (m_matrix[0][2] * FX_ + m_matrix[1][2] * FY_ + m_matrix[2][2]); \
if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
- w = 1./w; \
+ w = qreal(1.)/w; \
nx *= w; \
ny *= w; \
} \
@@ -213,6 +177,7 @@ static void nanWarning(const char *func)
transformation is achieved by setting both the projection factors and
the scaling factors.
+ \section2 Combining Transforms
Here's the combined transformations example using basic matrix
operations:
@@ -223,6 +188,26 @@ static void nanWarning(const char *func)
\snippet transform/main.cpp 2
\endtable
+ The combined transform first scales each operand, then rotates it, and
+ finally translates it, just as in the order in which the product of its
+ factors is written. This means the point to which the transforms are
+ applied is implicitly multiplied on the left with the transform
+ to its right.
+
+ \section2 Relation to Matrix Notation
+ The matrix notation in QTransform is the transpose of a commonly-taught
+ convention which represents transforms and points as matrices and vectors.
+ That convention multiplies its matrix on the left and column vector to the
+ right. In other words, when several transforms are applied to a point, the
+ right-most matrix acts directly on the vector first. Then the next matrix
+ to the left acts on the result of the first operation - and so on. As a
+ result, that convention multiplies the matrices that make up a composite
+ transform in the reverse of the order in QTransform, as you can see in
+ \l {Combining Transforms}. Transposing the matrices, and combining them to
+ the right of a row vector that represents the point, lets the matrices of
+ transforms appear, in their product, in the order in which we think of the
+ transforms being applied to the point.
+
\sa QPainter, {Coordinate System}, {painting/affine}{Affine
Transformations Example}, {Transformations Example}
*/
@@ -373,7 +358,7 @@ QTransform &QTransform::translate(qreal dx, qreal dy)
if (dx == 0 && dy == 0)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(dx) | qIsNaN(dy)) {
+ if (qIsNaN(dx) || qIsNaN(dy)) {
nanWarning("translate");
return *this;
}
@@ -416,7 +401,7 @@ QTransform &QTransform::translate(qreal dx, qreal dy)
QTransform QTransform::fromTranslate(qreal dx, qreal dy)
{
#ifndef QT_NO_DEBUG
- if (qIsNaN(dx) | qIsNaN(dy)) {
+ if (qIsNaN(dx) || qIsNaN(dy)) {
nanWarning("fromTranslate");
return QTransform();
}
@@ -441,7 +426,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
if (sx == 1 && sy == 1)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(sx) | qIsNaN(sy)) {
+ if (qIsNaN(sx) || qIsNaN(sy)) {
nanWarning("scale");
return *this;
}
@@ -482,7 +467,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
QTransform QTransform::fromScale(qreal sx, qreal sy)
{
#ifndef QT_NO_DEBUG
- if (qIsNaN(sx) | qIsNaN(sy)) {
+ if (qIsNaN(sx) || qIsNaN(sy)) {
nanWarning("fromScale");
return QTransform();
}
@@ -507,7 +492,7 @@ QTransform & QTransform::shear(qreal sh, qreal sv)
if (sh == 0 && sv == 0)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(sh) | qIsNaN(sv)) {
+ if (qIsNaN(sh) || qIsNaN(sv)) {
nanWarning("shear");
return *this;
}
@@ -548,29 +533,33 @@ QTransform & QTransform::shear(qreal sh, qreal sv)
return *this;
}
-const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
-const qreal inv_dist_to_plane = 1. / 1024.;
-
/*!
- \fn QTransform &QTransform::rotate(qreal angle, Qt::Axis axis)
+ \since 6.5
- Rotates the coordinate system counterclockwise by the given \a angle
- about the specified \a axis and returns a reference to the matrix.
+ Rotates the coordinate system counterclockwise by the given angle \a a
+ about the specified \a axis at distance \a distanceToPlane from the
+ screen and returns a reference to the matrix.
+//! [transform-rotate-note]
Note that if you apply a QTransform to a point defined in widget
coordinates, the direction of the rotation will be clockwise
because the y-axis points downwards.
The angle is specified in degrees.
+//! [transform-rotate-note]
+
+ If \a distanceToPlane is zero, it will be ignored. This is suitable
+ for implementing orthographic projections where the z coordinate should
+ be dropped rather than projected.
\sa setMatrix()
*/
-QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
+QTransform & QTransform::rotate(qreal a, Qt::Axis axis, qreal distanceToPlane)
{
if (a == 0)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(a)) {
+ if (qIsNaN(a) || qIsNaN(distanceToPlane)) {
nanWarning("rotate");
return *this;
}
@@ -585,7 +574,7 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
else if (a == 180.)
cosa = -1.;
else{
- qreal b = deg2rad*a; // convert to radians
+ qreal b = qDegreesToRadians(a);
sina = qSin(b); // fast and convenient
cosa = qCos(b);
}
@@ -633,13 +622,16 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
if (m_dirty < TxRotate)
m_dirty = TxRotate;
} else {
+ if (!qIsNull(distanceToPlane))
+ sina /= distanceToPlane;
+
QTransform result;
if (axis == Qt::YAxis) {
result.m_matrix[0][0] = cosa;
- result.m_matrix[0][2] = -sina * inv_dist_to_plane;
+ result.m_matrix[0][2] = -sina;
} else {
result.m_matrix[1][1] = cosa;
- result.m_matrix[1][2] = -sina * inv_dist_to_plane;
+ result.m_matrix[1][2] = -sina;
}
result.m_type = TxProject;
*this = result * *this;
@@ -648,24 +640,49 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
return *this;
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
- \fn QTransform & QTransform::rotateRadians(qreal angle, Qt::Axis axis)
+ \overload
+
+ Rotates the coordinate system counterclockwise by the given angle \a a
+ about the specified \a axis at distance 1024.0 from the screen and
+ returns a reference to the matrix.
+
+ \include qtransform.cpp transform-rotate-note
- Rotates the coordinate system counterclockwise by the given \a angle
- about the specified \a axis and returns a reference to the matrix.
+ \sa setMatrix
+*/
+QTransform &QTransform::rotate(qreal a, Qt::Axis axis)
+{
+ return rotate(a, axis, 1024.0);
+}
+#endif
+
+/*!
+ \since 6.5
+ Rotates the coordinate system counterclockwise by the given angle \a a
+ about the specified \a axis at distance \a distanceToPlane from the
+ screen and returns a reference to the matrix.
+
+//! [transform-rotate-radians-note]
Note that if you apply a QTransform to a point defined in widget
coordinates, the direction of the rotation will be clockwise
because the y-axis points downwards.
The angle is specified in radians.
+//! [transform-rotate-radians-note]
+
+ If \a distanceToPlane is zero, it will be ignored. This is suitable
+ for implementing orthographic projections where the z coordinate should
+ be dropped rather than projected.
\sa setMatrix()
*/
-QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
+QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis, qreal distanceToPlane)
{
#ifndef QT_NO_DEBUG
- if (qIsNaN(a)) {
+ if (qIsNaN(a) || qIsNaN(distanceToPlane)) {
nanWarning("rotateRadians");
return *this;
}
@@ -716,13 +733,16 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
if (m_dirty < TxRotate)
m_dirty = TxRotate;
} else {
+ if (!qIsNull(distanceToPlane))
+ sina /= distanceToPlane;
+
QTransform result;
if (axis == Qt::YAxis) {
result.m_matrix[0][0] = cosa;
- result.m_matrix[0][2] = -sina * inv_dist_to_plane;
+ result.m_matrix[0][2] = -sina;
} else {
result.m_matrix[1][1] = cosa;
- result.m_matrix[1][2] = -sina * inv_dist_to_plane;
+ result.m_matrix[1][2] = -sina;
}
result.m_type = TxProject;
*this = result * *this;
@@ -730,6 +750,24 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
return *this;
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+/*!
+ \overload
+
+ Rotates the coordinate system counterclockwise by the given angle \a a
+ about the specified \a axis at distance 1024.0 from the screen and
+ returns a reference to the matrix.
+
+ \include qtransform.cpp transform-rotate-radians-note
+
+ \sa setMatrix()
+*/
+QTransform &QTransform::rotateRadians(qreal a, Qt::Axis axis)
+{
+ return rotateRadians(a, axis, 1024.0);
+}
+#endif
+
/*!
\fn bool QTransform::operator==(const QTransform &matrix) const
Returns \c true if this matrix is equal to the given \a matrix,
@@ -1107,30 +1145,8 @@ QPoint QTransform::map(const QPoint &p) const
qreal x = 0, y = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x = fx;
- y = fy;
- break;
- case TxTranslate:
- x = fx + m_matrix[2][0];
- y = fy + m_matrix[2][1];
- break;
- case TxScale:
- x = m_matrix[0][0] * fx + m_matrix[2][0];
- y = m_matrix[1][1] * fy + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = m_matrix[0][0] * fx + m_matrix[1][0] * fy + m_matrix[2][0];
- y = m_matrix[0][1] * fx + m_matrix[1][1] * fy + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx + m_matrix[1][2] * fy + m_matrix[2][2]);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPoint(qRound(x), qRound(y));
}
@@ -1158,30 +1174,8 @@ QPointF QTransform::map(const QPointF &p) const
qreal x = 0, y = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x = fx;
- y = fy;
- break;
- case TxTranslate:
- x = fx + m_matrix[2][0];
- y = fy + m_matrix[2][1];
- break;
- case TxScale:
- x = m_matrix[0][0] * fx + m_matrix[2][0];
- y = m_matrix[1][1] * fy + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = m_matrix[0][0] * fx + m_matrix[1][0] * fy + m_matrix[2][0];
- y = m_matrix[0][1] * fx + m_matrix[1][1] * fy + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx + m_matrix[1][2] * fy + m_matrix[2][2]);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPointF(x, y);
}
@@ -1229,41 +1223,9 @@ QLine QTransform::map(const QLine &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x1 = fx1;
- y1 = fy1;
- x2 = fx2;
- y2 = fy2;
- break;
- case TxTranslate:
- x1 = fx1 + m_matrix[2][0];
- y1 = fy1 + m_matrix[2][1];
- x2 = fx2 + m_matrix[2][0];
- y2 = fy2 + m_matrix[2][1];
- break;
- case TxScale:
- x1 = m_matrix[0][0] * fx1 + m_matrix[2][0];
- y1 = m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[2][0];
- y2 = m_matrix[1][1] * fy2 + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = m_matrix[0][0] * fx1 + m_matrix[1][0] * fy1 + m_matrix[2][0];
- y1 = m_matrix[0][1] * fx1 + m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[1][0] * fy2 + m_matrix[2][0];
- y2 = m_matrix[0][1] * fx2 + m_matrix[1][1] * fy2 + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx1 + m_matrix[1][2] * fy1 + m_matrix[2][2]);
- x1 *= w;
- y1 *= w;
- w = 1./(m_matrix[0][2] * fx2 + m_matrix[1][2] * fy2 + m_matrix[2][2]);
- x2 *= w;
- y2 *= w;
- }
- }
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
+
return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
}
@@ -1288,66 +1250,12 @@ QLineF QTransform::map(const QLineF &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x1 = fx1;
- y1 = fy1;
- x2 = fx2;
- y2 = fy2;
- break;
- case TxTranslate:
- x1 = fx1 + m_matrix[2][0];
- y1 = fy1 + m_matrix[2][1];
- x2 = fx2 + m_matrix[2][0];
- y2 = fy2 + m_matrix[2][1];
- break;
- case TxScale:
- x1 = m_matrix[0][0] * fx1 + m_matrix[2][0];
- y1 = m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[2][0];
- y2 = m_matrix[1][1] * fy2 + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = m_matrix[0][0] * fx1 + m_matrix[1][0] * fy1 + m_matrix[2][0];
- y1 = m_matrix[0][1] * fx1 + m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[1][0] * fy2 + m_matrix[2][0];
- y2 = m_matrix[0][1] * fx2 + m_matrix[1][1] * fy2 + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx1 + m_matrix[1][2] * fy1 + m_matrix[2][2]);
- x1 *= w;
- y1 *= w;
- w = 1./(m_matrix[0][2] * fx2 + m_matrix[1][2] * fy2 + m_matrix[2][2]);
- x2 *= w;
- y2 *= w;
- }
- }
- return QLineF(x1, y1, x2, y2);
-}
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
-static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &poly)
-{
- if (poly.size() == 0)
- return poly;
-
- if (poly.size() == 1)
- return QPolygonF() << transform.map(poly.at(0));
-
- QPainterPath path;
- path.addPolygon(poly);
-
- path = transform.map(path);
-
- QPolygonF result;
- const int elementCount = path.elementCount();
- result.reserve(elementCount);
- for (int i = 0; i < elementCount; ++i)
- result << path.elementAt(i);
- return result;
+ return QLineF(x1, y1, x2, y2);
}
-
/*!
\fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix)
\since 4.3
@@ -1381,9 +1289,6 @@ QPolygonF QTransform::map(const QPolygonF &a) const
if (t <= TxTranslate)
return a.translated(m_matrix[2][0], m_matrix[2][1]);
- if (t >= QTransform::TxProject)
- return mapProjective(*this, a);
-
int size = a.size();
int i;
QPolygonF p(size);
@@ -1411,9 +1316,6 @@ QPolygon QTransform::map(const QPolygon &a) const
if (t <= TxTranslate)
return a.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
- if (t >= QTransform::TxProject)
- return mapProjective(*this, QPolygonF(a)).toPolygon();
-
int size = a.size();
int i;
QPolygon p(size);
@@ -1466,16 +1368,16 @@ QRegion QTransform::map(const QRegion &r) const
QRegion res;
if (m11() < 0 || m22() < 0) {
for (const QRect &rect : r)
- res += mapRect(QRectF(rect)).toRect();
+ res += qt_mapFillRect(QRectF(rect), *this);
} else {
QVarLengthArray<QRect, 32> rects;
rects.reserve(r.rectCount());
for (const QRect &rect : r) {
- QRect nr = mapRect(QRectF(rect)).toRect();
+ QRect nr = qt_mapFillRect(QRectF(rect), *this);
if (!nr.isEmpty())
rects.append(nr);
}
- res.setRects(rects.constData(), rects.count());
+ res.setRects(rects.constData(), rects.size());
}
return res;
}
@@ -1704,7 +1606,7 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const
MAP(rect.x(), bottom, x[3], y[3]);
}
- // all coordinates are correctly, tranform to a pointarray
+ // all coordinates are correctly, transform to a pointarray
// (rounding to the next integer)
a.setPoints(4, qRound(x[0]), qRound(y[0]),
qRound(x[1]), qRound(y[1]),
@@ -1722,7 +1624,7 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const
*/
bool QTransform::squareToQuad(const QPolygonF &quad, QTransform &trans)
{
- if (quad.count() != 4)
+ if (quad.size() != 4)
return false;
qreal dx0 = quad[0].x();
@@ -1844,14 +1746,6 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
m_dirty = TxProject;
}
-static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
-{
- const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
- const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
-
- return wx + wy + transform.m33() < Q_NEAR_CLIP;
-}
-
QRect QTransform::mapRect(const QRect &rect) const
{
TransformationType t = inline_type();
@@ -1872,8 +1766,7 @@ QRect QTransform::mapRect(const QRect &rect) const
y -= h;
}
return QRect(x, y, w, h);
- } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
- // see mapToPolygon for explanations of the algorithm.
+ } else {
qreal x = 0, y = 0;
MAP(rect.left(), rect.top(), x, y);
qreal xmin = x;
@@ -1895,11 +1788,7 @@ QRect QTransform::mapRect(const QRect &rect) const
ymin = qMin(ymin, y);
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
- return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
- } else {
- QPainterPath path;
- path.addRect(rect);
- return map(path).boundingRect().toRect();
+ return QRectF(xmin, ymin, xmax-xmin, ymax-ymin).toRect();
}
}
@@ -1942,7 +1831,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
y -= h;
}
return QRectF(x, y, w, h);
- } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
+ } else {
qreal x = 0, y = 0;
MAP(rect.x(), rect.y(), x, y);
qreal xmin = x;
@@ -1965,10 +1854,6 @@ QRectF QTransform::mapRect(const QRectF &rect) const
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
- } else {
- QPainterPath path;
- path.addRect(rect);
- return map(path).boundingRect();
}
}
@@ -2033,7 +1918,7 @@ void QTransform::map(int x, int y, int *tx, int *ty) const
*/
QTransform::TransformationType QTransform::type() const
{
- if(m_dirty == TxNone || m_dirty < m_type)
+ if (m_dirty == TxNone || m_dirty < m_type)
return static_cast<TransformationType>(m_type);
switch (static_cast<TransformationType>(m_dirty)) {
@@ -2046,7 +1931,7 @@ QTransform::TransformationType QTransform::type() const
case TxShear:
case TxRotate:
if (!qFuzzyIsNull(m_matrix[0][1]) || !qFuzzyIsNull(m_matrix[1][0])) {
- const qreal dot = m_matrix[0][0] * m_matrix[0][1] + m_matrix[1][0] * m_matrix[1][1];
+ const qreal dot = m_matrix[0][0] * m_matrix[1][0] + m_matrix[0][1] * m_matrix[1][1];
if (qFuzzyIsNull(dot))
m_type = TxRotate;
else
@@ -2081,7 +1966,7 @@ QTransform::TransformationType QTransform::type() const
*/
QTransform::operator QVariant() const
{
- return QVariant(QMetaType::QTransform, this);
+ return QVariant::fromValue(*this);
}
diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h
index 972e45146a..e5b245d8c9 100644
--- a/src/gui/painting/qtransform.h
+++ b/src/gui/painting/qtransform.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTRANSFORM_H
#define QTRANSFORM_H
@@ -113,15 +77,24 @@ public:
qreal m21, qreal m22, qreal m23,
qreal m31, qreal m32, qreal m33);
- Q_REQUIRED_RESULT QTransform inverted(bool *invertible = nullptr) const;
- Q_REQUIRED_RESULT QTransform adjoint() const;
- Q_REQUIRED_RESULT QTransform transposed() const;
+ [[nodiscard]] QTransform inverted(bool *invertible = nullptr) const;
+ [[nodiscard]] QTransform adjoint() const;
+ [[nodiscard]] QTransform transposed() const;
QTransform &translate(qreal dx, qreal dy);
QTransform &scale(qreal sx, qreal sy);
QTransform &shear(qreal sh, qreal sv);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QTransform &rotate(qreal a, Qt::Axis axis, qreal distanceToPlane);
+ // ### Qt7: Remove
QTransform &rotate(qreal a, Qt::Axis axis = Qt::ZAxis);
+ QTransform &rotateRadians(qreal a, Qt::Axis axis, qreal distanceToPlane);
+ // ### Qt7: Remove
QTransform &rotateRadians(qreal a, Qt::Axis axis = Qt::ZAxis);
+#else
+ QTransform &rotate(qreal a, Qt::Axis axis = Qt::ZAxis, qreal distanceToPlane = 1024.0f);
+ QTransform &rotateRadians(qreal a, Qt::Axis axis = Qt::ZAxis, qreal distanceToPlane = 1024.0f);
+#endif
static bool squareToQuad(const QPolygonF &square, QTransform &result);
static bool quadToSquare(const QPolygonF &quad, QTransform &result);
@@ -177,7 +150,7 @@ private:
mutable uint m_type : 5;
mutable uint m_dirty : 5;
};
-Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QTransform, Q_RELOCATABLE_TYPE);
Q_GUI_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(const QTransform &key, size_t seed = 0) noexcept;
diff --git a/src/gui/painting/qtriangulatingstroker.cpp b/src/gui/painting/qtriangulatingstroker.cpp
index 14acc1a480..c8d2e90397 100644
--- a/src/gui/painting/qtriangulatingstroker.cpp
+++ b/src/gui/painting/qtriangulatingstroker.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtriangulatingstroker_p.h"
#include <qmath.h>
@@ -50,6 +14,7 @@ QT_BEGIN_NAMESPACE
void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur,
bool implicitClose, bool endsAtStart)
{
+ Q_ASSERT(start);
if (endsAtStart) {
join(start + 2);
} else if (implicitClose) {
@@ -79,11 +44,12 @@ static inline void skipDuplicatePoints(const qreal **pts, const qreal *endPts)
}
}
-void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &, QPainter::RenderHints hints)
+void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &, QPainter::RenderHints)
{
const qreal *pts = path.points();
const QPainterPath::ElementType *types = path.elements();
int count = path.elementCount();
+ m_vertices.reset();
if (count < 2)
return;
@@ -93,14 +59,13 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, co
m_width = realWidth / 2;
- bool cosmetic = qt_pen_is_cosmetic(pen, hints);
+ bool cosmetic = pen.isCosmetic();
if (cosmetic) {
m_width = m_width * m_inv_scale;
}
m_join_style = qpen_joinStyle(pen);
m_cap_style = qpen_capStyle(pen);
- m_vertices.reset();
m_miter_limit = pen.miterLimit() * qpen_widthf(pen);
// The curvyness is based on the notion that I originally wanted
@@ -537,14 +502,14 @@ QDashedStrokeProcessor::QDashedStrokeProcessor()
m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo);
}
-void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints hints)
+void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip, QPainter::RenderHints)
{
const qreal *pts = path.points();
const QPainterPath::ElementType *types = path.elements();
int count = path.elementCount();
- bool cosmetic = qt_pen_is_cosmetic(pen, hints);
+ bool cosmetic = pen.isCosmetic();
bool implicitClose = path.hasImplicitClose();
m_points.reset();
diff --git a/src/gui/painting/qtriangulatingstroker_p.h b/src/gui/painting/qtriangulatingstroker_p.h
index 2b0f08972b..cd038b0d45 100644
--- a/src/gui/painting/qtriangulatingstroker_p.h
+++ b/src/gui/painting/qtriangulatingstroker_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTRIANGULATINGSTROKER_P_H
#define QTRIANGULATINGSTROKER_P_H
@@ -51,6 +15,7 @@
// We mean it.
//
+#include <QtCore/qmath.h>
#include <QtGui/private/qtguiglobal_p.h>
#include <private/qdatabuffer_p.h>
#include <qvarlengtharray.h>
@@ -134,18 +99,9 @@ private:
inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, float y2,
float *nx, float *ny)
{
- float dx = x2 - x1;
- float dy = y2 - y1;
- Q_ASSERT(dx != 0 || dy != 0);
-
- float pw;
-
- if (dx == 0)
- pw = m_width / std::abs(dy);
- else if (dy == 0)
- pw = m_width / std::abs(dx);
- else
- pw = m_width / std::sqrt(dx*dx + dy*dy);
+ const float dx = x2 - x1;
+ const float dy = y2 - y1;
+ const float pw = m_width / qHypot(dx, dy);
*nx = -dy * pw;
*ny = dx * pw;
diff --git a/src/gui/painting/qtriangulator.cpp b/src/gui/painting/qtriangulator.cpp
index eab06d4d4c..029566f1b9 100644
--- a/src/gui/painting/qtriangulator.cpp
+++ b/src/gui/painting/qtriangulator.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtriangulator_p.h"
@@ -66,8 +30,8 @@ struct QVertexSet
QVertexSet<T> &operator = (const QVertexSet<T> &other) {vertices = other.vertices; indices = other.indices; return *this;}
// The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ...
- QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
- QVector<T> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
+ QList<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
+ QList<T> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
};
//============================================================================//
@@ -570,8 +534,8 @@ public:
class ComplexToSimple
{
public:
- inline ComplexToSimple(QTriangulator<T> *parent) : m_parent(parent),
- m_edges(0), m_events(0), m_splits(0) { }
+ inline ComplexToSimple(QTriangulator<T> *parent)
+ : m_parent(parent), m_edges(0), m_events(0), m_splits(0), m_initialPointCount(0) { }
void decompose();
private:
struct Edge
@@ -674,7 +638,8 @@ public:
class SimpleToMonotone
{
public:
- inline SimpleToMonotone(QTriangulator<T> *parent) : m_parent(parent), m_edges(0), m_upperVertex(0) { }
+ inline SimpleToMonotone(QTriangulator<T> *parent)
+ : m_parent(parent), m_edges(0), m_upperVertex(0), m_clockwiseOrder(false) { }
void decompose();
private:
enum VertexType {MergeVertex, EndVertex, RegularVertex, StartVertex, SplitVertex};
@@ -730,7 +695,8 @@ public:
class MonotoneToTriangles
{
public:
- inline MonotoneToTriangles(QTriangulator<T> *parent) : m_parent(parent) { }
+ inline MonotoneToTriangles(QTriangulator<T> *parent)
+ : m_parent(parent), m_first(0), m_length(0) { }
void decompose();
private:
inline T indices(int index) const {return m_parent->m_indices.at(index + m_first);}
@@ -748,7 +714,8 @@ public:
int m_length;
};
- inline QTriangulator() : m_vertices(0) { }
+ inline QTriangulator()
+ : m_vertices(0), m_hint(0) { }
// Call this only once.
void initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix);
@@ -761,7 +728,7 @@ public:
QVertexSet<T> polyline();
private:
QDataBuffer<QPodPoint> m_vertices;
- QVector<T> m_indices;
+ QList<T> m_indices;
uint m_hint;
};
@@ -1061,7 +1028,7 @@ template <typename T>
QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator<T>::ComplexToSimple::bounds(const QPodPoint &point) const
{
QRBTree<int>::Node *current = m_edgeList.root;
- QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(0, 0);
+ QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(nullptr, nullptr);
while (current) {
const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper());
@@ -1110,7 +1077,7 @@ template <typename T>
QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator<T>::ComplexToSimple::outerBounds(const QPodPoint &point) const
{
QRBTree<int>::Node *current = m_edgeList.root;
- QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(0, 0);
+ QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> result(nullptr, nullptr);
while (current) {
const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower());
@@ -1309,7 +1276,7 @@ void QTriangulator<T>::ComplexToSimple::calculateIntersections()
int vertex = (event.type == Event::Upper ? m_edges.at(event.edge).upper() : m_edges.at(event.edge).lower());
QIntersectionPoint eventPoint = QT_PREPEND_NAMESPACE(qIntersectionPoint)(event.point);
- if (range.first != 0) {
+ if (range.first != nullptr) {
splitEdgeListRange(range.first, range.second, vertex, eventPoint);
reorderEdgeListRange(range.first, range.second);
}
@@ -2155,7 +2122,7 @@ bool QTriangulator<T>::SimpleToMonotone::CompareVertices::operator () (int i, in
template <typename T>
void QTriangulator<T>::MonotoneToTriangles::decompose()
{
- QVector<T> result;
+ QList<T> result;
QDataBuffer<int> stack(m_parent->m_indices.size());
m_first = 0;
// Require at least three more indices.
@@ -2354,3 +2321,5 @@ QPolylineSet qPolyline(const QPainterPath &path,
}
QT_END_NAMESPACE
+
+#undef Q_FIXED_POINT_SCALE
diff --git a/src/gui/painting/qtriangulator_p.h b/src/gui/painting/qtriangulator_p.h
index e07fcae090..09db3f1619 100644
--- a/src/gui/painting/qtriangulator_p.h
+++ b/src/gui/painting/qtriangulator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QTRIANGULATOR_P_H
#define QTRIANGULATOR_P_H
diff --git a/src/gui/painting/qvectorpath_p.h b/src/gui/painting/qvectorpath_p.h
index df5772d4cc..b99d8fd857 100644
--- a/src/gui/painting/qvectorpath_p.h
+++ b/src/gui/painting/qvectorpath_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QVECTORPATH_P_H
#define QVECTORPATH_P_H
diff --git a/src/gui/painting/shaders/backingstorecompose.frag b/src/gui/painting/shaders/backingstorecompose.frag
new file mode 100644
index 0000000000..3b08ade035
--- /dev/null
+++ b/src/gui/painting/shaders/backingstorecompose.frag
@@ -0,0 +1,25 @@
+#version 440
+
+layout(location = 0) in vec2 v_texcoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 vertexTransform;
+ mat3 textureTransform;
+ float opacity;
+ int textureSwizzle;
+};
+
+layout(binding = 1) uniform sampler2D textureSampler;
+
+void main()
+{
+ vec4 tmpFragColor = texture(textureSampler, v_texcoord);
+ tmpFragColor.a *= opacity;
+ if (textureSwizzle == 0)
+ fragColor = tmpFragColor;
+ else if(textureSwizzle == 2)
+ fragColor.argb = tmpFragColor;
+ else
+ fragColor.bgra = tmpFragColor;
+}
diff --git a/src/gui/painting/shaders/backingstorecompose.frag.qsb b/src/gui/painting/shaders/backingstorecompose.frag.qsb
new file mode 100644
index 0000000000..63ba55eed8
--- /dev/null
+++ b/src/gui/painting/shaders/backingstorecompose.frag.qsb
Binary files differ
diff --git a/src/gui/painting/shaders/backingstorecompose.vert b/src/gui/painting/shaders/backingstorecompose.vert
new file mode 100644
index 0000000000..0c72c97419
--- /dev/null
+++ b/src/gui/painting/shaders/backingstorecompose.vert
@@ -0,0 +1,19 @@
+#version 440
+
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec2 texcoord;
+
+layout(location = 0) out vec2 v_texcoord;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 vertexTransform;
+ mat3 textureTransform;
+ float opacity;
+ int textureSwizzle;
+};
+
+void main()
+{
+ v_texcoord = (textureTransform * vec3(texcoord, 1.0)).xy;
+ gl_Position = vertexTransform * vec4(position, 1.0);
+}
diff --git a/src/gui/painting/shaders/backingstorecompose.vert.qsb b/src/gui/painting/shaders/backingstorecompose.vert.qsb
new file mode 100644
index 0000000000..1aa6e661f8
--- /dev/null
+++ b/src/gui/painting/shaders/backingstorecompose.vert.qsb
Binary files differ
diff --git a/src/gui/painting/webgradients.cpp b/src/gui/painting/webgradients.cpp
index b4d297450b..fd5031349e 100644
--- a/src/gui/painting/webgradients.cpp
+++ b/src/gui/painting/webgradients.cpp
@@ -1,45 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// This file is auto-generated by gradientgen. DO NOT EDIT!
-static QArrayDataPointerRef<QGradientStop> qt_preset_gradient_stops(QGradient::Preset preset)
+static QList<QGradientStop> qt_preset_gradient_stops(QGradient::Preset preset)
{
Q_ASSERT(preset < QGradient::NumPresets);
switch (preset) {
@@ -382,11 +346,10 @@ static QArrayDataPointerRef<QGradientStop> qt_preset_gradient_stops(QGradient::P
case QGradient::NumPresets:
Q_UNREACHABLE();
}
- Q_UNREACHABLE();
- return {};
+ Q_UNREACHABLE_RETURN({});
}
-static Q_CONSTEXPR QGradient::QGradientData qt_preset_gradient_data[] = {
+static constexpr QGradient::QGradientData qt_preset_gradient_data[] = {
{ { 0, 1, 1, 0 } },
{ { 0.5, 1, 0.5, 0 } },
{ { 0.5, 1, 0.5, 0 } },
@@ -568,11 +531,3 @@ static Q_CONSTEXPR QGradient::QGradientData qt_preset_gradient_data[] = {
{ { 0, 0, 1, 1 } },
{ { 0, 0, 1, 1 } },
};
-
-static void *qt_preset_gradient_dummy()
-{
- union {void *p; uint i;};
- p = 0;
- i |= uint(QGradient::ObjectMode);
- return p;
-}