summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/WEBGRADIENTS_LICENSE.txt21
-rw-r--r--src/gui/painting/painting.pri175
-rw-r--r--src/gui/painting/qbackingstore.cpp165
-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.h46
-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.cpp468
-rw-r--r--src/gui/painting/qbrush.h96
-rw-r--r--src/gui/painting/qcmyk_p.h88
-rw-r--r--src/gui/painting/qcolor.cpp794
-rw-r--r--src/gui/painting/qcolor.h519
-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.h299
-rw-r--r--src/gui/painting/qcolorspace.cpp990
-rw-r--r--src/gui/painting/qcolorspace.h126
-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.h201
-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.mm215
-rw-r--r--src/gui/painting/qcoregraphics_p.h75
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp155
-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.h68
-rw-r--r--src/gui/painting/qdrawhelper.cpp4354
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp481
-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.cpp71
-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.h473
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp150
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp252
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp44
-rw-r--r--src/gui/painting/qdrawhelper_x86_p.h43
-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.cpp1089
-rw-r--r--src/gui/painting/qicc_p.h41
-rw-r--r--src/gui/painting/qimageeffects.cpp327
-rw-r--r--src/gui/painting/qimagescale.cpp907
-rw-r--r--src/gui/painting/qimagescale_neon.cpp238
-rw-r--r--src/gui/painting/qimagescale_p.h43
-rw-r--r--src/gui/painting/qimagescale_sse4.cpp266
-rw-r--r--src/gui/painting/qmath_p.h56
-rw-r--r--src/gui/painting/qmatrix.cpp1190
-rw-r--r--src/gui/painting/qmatrix.h194
-rw-r--r--src/gui/painting/qmemrotate.cpp151
-rw-r--r--src/gui/painting/qmemrotate_p.h42
-rw-r--r--src/gui/painting/qoutlinemapper.cpp74
-rw-r--r--src/gui/painting/qoutlinemapper_p.h56
-rw-r--r--src/gui/painting/qpagedpaintdevice.cpp355
-rw-r--r--src/gui/painting/qpagedpaintdevice.h225
-rw-r--r--src/gui/painting/qpagedpaintdevice_p.h47
-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.cpp103
-rw-r--r--src/gui/painting/qpagesize.h81
-rw-r--r--src/gui/painting/qpaintdevice.cpp41
-rw-r--r--src/gui/painting/qpaintdevice.h47
-rw-r--r--src/gui/painting/qpaintdevice.qdoc35
-rw-r--r--src/gui/painting/qpaintengine.cpp94
-rw-r--r--src/gui/painting/qpaintengine.h51
-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.cpp560
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h71
-rw-r--r--src/gui/painting/qpaintengineex.cpp100
-rw-r--r--src/gui/painting/qpaintengineex_p.h40
-rw-r--r--src/gui/painting/qpainter.cpp981
-rw-r--r--src/gui/painting/qpainter.h156
-rw-r--r--src/gui/painting/qpainter_p.h113
-rw-r--r--src/gui/painting/qpainterpath.cpp331
-rw-r--r--src/gui/painting/qpainterpath.h109
-rw-r--r--src/gui/painting/qpainterpath_p.h195
-rw-r--r--src/gui/painting/qpathclipper.cpp66
-rw-r--r--src/gui/painting/qpathclipper_p.h54
-rw-r--r--src/gui/painting/qpathsimplifier.cpp62
-rw-r--r--src/gui/painting/qpathsimplifier_p.h40
-rw-r--r--src/gui/painting/qpdf.cpp829
-rw-r--r--src/gui/painting/qpdf.qrc7
-rw-r--r--src/gui/painting/qpdf_p.h153
-rw-r--r--src/gui/painting/qpdfwriter.cpp233
-rw-r--r--src/gui/painting/qpdfwriter.h73
-rw-r--r--src/gui/painting/qpen.cpp216
-rw-r--r--src/gui/painting/qpen.h63
-rw-r--r--src/gui/painting/qpen_p.h52
-rw-r--r--src/gui/painting/qpixellayout.cpp2436
-rw-r--r--src/gui/painting/qpixellayout_p.h335
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp604
-rw-r--r--src/gui/painting/qplatformbackingstore.h142
-rw-r--r--src/gui/painting/qpolygon.cpp184
-rw-r--r--src/gui/painting/qpolygon.h167
-rw-r--r--src/gui/painting/qpolygonclipper_p.h316
-rw-r--r--src/gui/painting/qrasterbackingstore.cpp83
-rw-r--r--src/gui/painting/qrasterbackingstore_p.h46
-rw-r--r--src/gui/painting/qrasterdefs_p.h48
-rw-r--r--src/gui/painting/qrasterizer.cpp597
-rw-r--r--src/gui/painting/qrasterizer_p.h41
-rw-r--r--src/gui/painting/qrbtree_p.h44
-rw-r--r--src/gui/painting/qregion.cpp240
-rw-r--r--src/gui/painting/qregion.h101
-rw-r--r--src/gui/painting/qrgb.h62
-rw-r--r--src/gui/painting/qrgba64.h112
-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.h57
-rw-r--r--src/gui/painting/qt_attribution.json30
-rw-r--r--src/gui/painting/qt_mips_asm_dsp_p.h46
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp90
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h72
-rw-r--r--src/gui/painting/qtransform.cpp944
-rw-r--r--src/gui/painting/qtransform.h239
-rw-r--r--src/gui/painting/qtriangulatingstroker.cpp86
-rw-r--r--src/gui/painting/qtriangulatingstroker_p.h56
-rw-r--r--src/gui/painting/qtriangulator.cpp71
-rw-r--r--src/gui/painting/qtriangulator_p.h54
-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.binaryjsonbin50792 -> 0 bytes
-rw-r--r--src/gui/painting/webgradients.cpp533
-rw-r--r--src/gui/painting/webgradients.css909
158 files changed, 20266 insertions, 17445 deletions
diff --git a/src/gui/painting/WEBGRADIENTS_LICENSE.txt b/src/gui/painting/WEBGRADIENTS_LICENSE.txt
deleted file mode 100644
index 1a4d527a4d..0000000000
--- a/src/gui/painting/WEBGRADIENTS_LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017 itmeo
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
deleted file mode 100644
index fcf6488edd..0000000000
--- a/src/gui/painting/painting.pri
+++ /dev/null
@@ -1,175 +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/qmatrix.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/qpolygon.h \
- painting/qpolygonclipper_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/qmatrix.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/qpolygon.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
-
-webgradients.files = painting/webgradients.binaryjson
-webgradients.prefix = qgradient
-webgradients.base = painting
-
-RESOURCES += \
- painting/qpdf.qrc \
- webgradients
-
-darwin {
- HEADERS += painting/qcoregraphics_p.h
- SOURCES += painting/qcoregraphics.mm
-}
-
-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 {
- 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 b0393aff95..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.
@@ -220,8 +191,6 @@ static bool isRasterSurface(QWindow *window)
to the backingstore's top level window.
You should call this function after ending painting with endPaint().
-
- \sa QWindow::transientParent()
*/
void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &offset)
{
@@ -235,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);
}
/*!
@@ -263,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,15 +251,15 @@ QSize QBackingStore::size() const
bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
{
// Disable scrolling for non-integer scroll deltas. For this case
- // the the existing rendered pixels can't be re-used, and we return
+ // 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);
}
/*!
@@ -299,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;
}
@@ -322,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());
- int lineskip = img.bytesPerLine();
+ 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 1c49f82416..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
@@ -52,12 +16,10 @@
//
#include <QtGui/private/qtguiglobal_p.h>
-#include "QtCore/qpoint.h"
#include "QtCore/qline.h"
-#include "QtCore/qrect.h"
-#include "QtCore/qvector.h"
#include "QtCore/qlist.h"
-#include "QtCore/qpair.h"
+#include "QtCore/qpoint.h"
+#include "QtCore/qrect.h"
#include "QtGui/qtransform.h"
#include <private/qdatabuffer_p.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 b23fb45952..b053896233 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1,41 +1,6 @@
-/****************************************************************************
-**
-** 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.
+// 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"
@@ -53,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);
@@ -108,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)) {
@@ -230,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;
}
@@ -239,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
@@ -531,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();
}
@@ -558,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;
}
@@ -570,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)
@@ -590,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
@@ -613,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;
@@ -646,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;
}
@@ -671,7 +635,7 @@ QBrush &QBrush::operator=(const QBrush &b)
*/
QBrush::operator QVariant() const
{
- return QVariant(QVariant::Brush, this);
+ return QVariant::fromValue(*this);
}
/*!
@@ -747,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();
}
@@ -765,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);
@@ -788,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();
}
@@ -813,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);
@@ -829,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;
}
@@ -865,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)
@@ -879,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) {
@@ -891,21 +855,6 @@ bool QBrush::isOpaque() const
return false;
}
-
-/*!
- \since 4.2
-
- Sets \a matrix as an explicit transformation matrix on the
- current brush. The brush transformation matrix is merged with
- QPainter transformation matrix to produce the final result.
-
- \sa matrix()
-*/
-void QBrush::setMatrix(const QMatrix &matrix)
-{
- setTransform(QTransform(matrix));
-}
-
/*!
\since 4.3
@@ -923,15 +872,6 @@ void QBrush::setTransform(const QTransform &matrix)
/*!
- \fn void QBrush::matrix() const
- \since 4.2
-
- Returns the current transformation matrix for the brush.
-
- \sa setMatrix()
-*/
-
-/*!
\fn bool QBrush::operator!=(const QBrush &brush) const
Returns \c true if the brush is different from the given \a brush;
@@ -971,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;
@@ -997,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:
@@ -1012,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",
@@ -1033,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()] << ')';
@@ -1094,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);
@@ -1109,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();
@@ -1199,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;
@@ -1207,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;
@@ -1294,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
@@ -1335,7 +1281,7 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\internal
*/
QGradient::QGradient()
- : m_type(NoGradient), dummy(nullptr)
+ : m_type(NoGradient)
{
}
@@ -1344,8 +1290,179 @@ 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"
/*!
\fn QGradient::QGradient(QGradient::Preset preset)
@@ -1358,47 +1475,11 @@ QGradient::QGradient()
to be applied to arbitrary object sizes.
*/
QGradient::QGradient(Preset preset)
- : QGradient()
-{
- static QHash<int, QGradient> cachedPresets;
- static QMutex cacheMutex;
- QMutexLocker locker(&cacheMutex);
- if (cachedPresets.contains(preset)) {
- const QGradient &cachedPreset = cachedPresets.value(preset);
- m_type = cachedPreset.m_type;
- m_data = cachedPreset.m_data;
- m_stops = cachedPreset.m_stops;
- m_spread = cachedPreset.m_spread;
- dummy = cachedPreset.dummy;
- } else {
- static QJsonDocument jsonPresets = []() {
- QFile webGradients(QLatin1String(":/qgradient/webgradients.binaryjson"));
- webGradients.open(QFile::ReadOnly);
- return QJsonDocument::fromBinaryData(webGradients.readAll());
- }();
-
- const QJsonValue presetData = jsonPresets[preset - 1];
- if (!presetData.isObject())
- return;
-
- m_type = LinearGradient;
- setCoordinateMode(ObjectMode);
- setSpread(PadSpread);
-
- const QJsonValue start = presetData[QLatin1String("start")];
- const QJsonValue end = presetData[QLatin1String("end")];
- m_data.linear.x1 = start[QLatin1String("x")].toDouble();
- m_data.linear.y1 = start[QLatin1String("y")].toDouble();
- m_data.linear.x2 = end[QLatin1String("x")].toDouble();
- m_data.linear.y2 = end[QLatin1String("y")].toDouble();
-
- for (const QJsonValue &stop : presetData[QLatin1String("stops")].toArray()) {
- setColorAt(stop[QLatin1String("position")].toDouble(),
- QColor(QRgb(stop[QLatin1String("color")].toInt())));
- }
-
- cachedPresets.insert(preset, *this);
- }
+ : m_type(LinearGradient)
+ , m_stops(qt_preset_gradient_stops(preset))
+ , m_data(qt_preset_gradient_data[preset - 1])
+ , m_coordinateMode(ObjectMode)
+{
}
/*!
@@ -1408,11 +1489,6 @@ QGradient::~QGradient()
{
}
-QT_END_NAMESPACE
-static void initGradientPresets() { Q_INIT_RESOURCE(qmake_webgradients); }
-Q_CONSTRUCTOR_FUNCTION(initGradientPresets);
-QT_BEGIN_NAMESPACE
-
/*!
\enum QGradient::Type
@@ -1531,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;
@@ -1556,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
@@ -1597,8 +1671,7 @@ QGradientStops QGradient::stops() const
*/
QGradient::CoordinateMode QGradient::coordinateMode() const
{
- Q_DUMMY_ACCESSOR
- return CoordinateMode(i & 0x03);
+ return m_coordinateMode;
}
/*!
@@ -1609,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;
}
/*!
@@ -1635,8 +1705,7 @@ void QGradient::setCoordinateMode(CoordinateMode mode)
*/
QGradient::InterpolationMode QGradient::interpolationMode() const
{
- Q_DUMMY_ACCESSOR
- return InterpolationMode((i >> 2) & 0x01);
+ return m_interpolationMode;
}
/*!
@@ -1648,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;
}
/*!
@@ -1674,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
@@ -1687,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
@@ -1961,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();
@@ -1980,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();
}
@@ -2025,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;
}
@@ -2042,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();
@@ -2062,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;
@@ -2181,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;
}
/*!
@@ -2198,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;
}
/*!
@@ -2425,7 +2483,7 @@ void QConicalGradient::setAngle(qreal angle)
\typedef QGradientStops
\relates QGradient
- Typedef for QVector<QGradientStop>.
+ Typedef for QList<QGradientStop>.
*/
/*!
@@ -2453,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 6a4ffab1c5..ca8112ff31 100644
--- a/src/gui/painting/qbrush.h
+++ b/src/gui/painting/qbrush.h
@@ -1,55 +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
#ifndef QBRUSH_H
#define QBRUSH_H
#include <QtGui/qtguiglobal.h>
+#include <QtCore/qlist.h>
#include <QtCore/qpair.h>
#include <QtCore/qpoint.h>
-#include <QtCore/qvector.h>
#include <QtCore/qscopedpointer.h>
#include <QtGui/qcolor.h>
-#include <QtGui/qmatrix.h>
-#include <QtGui/qtransform.h>
#include <QtGui/qimage.h>
#include <QtGui/qpixmap.h>
+#include <QtGui/qtransform.h>
QT_BEGIN_NAMESPACE
@@ -58,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
{
@@ -79,19 +45,15 @@ 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;
inline Qt::BrushStyle style() const;
void setStyle(Qt::BrushStyle);
- inline const QMatrix &matrix() const;
- void setMatrix(const QMatrix &mat);
-
inline QTransform transform() const;
void setTransform(const QTransform &);
@@ -112,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;
@@ -120,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; }
};
@@ -157,7 +119,6 @@ struct QBrushData
inline Qt::BrushStyle QBrush::style() const { return d->style; }
inline const QColor &QBrush::color() const { return d->color; }
-inline const QMatrix &QBrush::matrix() const { return d->transform.toAffine(); }
inline QTransform QBrush::transform() const { return d->transform; }
inline bool QBrush::isDetached() const { return d->ref.loadRelaxed() == 1; }
@@ -168,7 +129,7 @@ inline bool QBrush::isDetached() const { return d->ref.loadRelaxed() == 1; }
class QGradientPrivate;
typedef QPair<qreal, QColor> QGradientStop;
-typedef QVector<QGradientStop> QGradientStops;
+typedef QList<QGradientStop> QGradientStops;
class Q_GUI_EXPORT QGradient
{
@@ -400,27 +361,30 @@ public:
inline bool operator!=(const QGradient &other) const
{ return !operator==(other); }
-private:
- friend class QLinearGradient;
- friend class QRadialGradient;
- friend class QConicalGradient;
- friend class QBrush;
-
- Type m_type;
- Spread m_spread;
- QGradientStops m_stops;
- union {
+ union QGradientData {
struct {
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;
} conical;
- } m_data;
- void *dummy; // ### Qt 6: replace with actual content (CoordinateMode, InterpolationMode, ...)
+ };
+
+private:
+ friend class QLinearGradient;
+ friend class QRadialGradient;
+ friend class QConicalGradient;
+ friend class QBrush;
+
+ Type m_type = NoGradient;
+ Spread m_spread = PadSpread;
+ QGradientStops m_stops;
+ QGradientData m_data;
+ 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 c567b25468..2af2e8cb6b 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** 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"
+#include "qdrawhelper_p.h"
#include "qfloat16.h"
#include "qnamespace.h"
#include "qdatastream.h"
@@ -47,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,
@@ -73,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;
@@ -89,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);
@@ -108,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
@@ -148,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[] = {
@@ -304,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)
@@ -311,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
@@ -358,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;
}
@@ -402,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
@@ -469,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.
@@ -610,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)
@@ -777,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.
*/
@@ -806,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)
@@ -828,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.
@@ -838,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
@@ -859,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('#') + QString::number(rgba() | 0x1000000, 16).rightRef(6);
+ return u'#' + QStringView{QString::number(rgba() | 0x1000000, 16)}.right(6);
case HexArgb:
// it's called rgba() but it does return AARRGGBB
- return QLatin1Char('#') + QString::number(rgba() | Q_INT64_C(0x100000000), 16).rightRef(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:
@@ -901,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.
@@ -939,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 {};
}
/*!
@@ -1013,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;
@@ -1023,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);
}
/*!
@@ -1052,11 +1053,11 @@ void QColor::getHsv(int *h, int *s, int *v, int *a) const
}
*h = ct.ahsv.hue == USHRT_MAX ? -1 : ct.ahsv.hue / 100;
- *s = ct.ahsv.saturation >> 8;
- *v = ct.ahsv.value >> 8;
+ *s = qt_div_257(ct.ahsv.saturation);
+ *v = qt_div_257(ct.ahsv.value);
if (a)
- *a = ct.ahsv.alpha >> 8;
+ *a = qt_div_257(ct.ahsv.alpha);
}
/*!
@@ -1067,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;
@@ -1080,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;
@@ -1123,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;
@@ -1133,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);
}
/*!
@@ -1164,11 +1165,11 @@ void QColor::getHsl(int *h, int *s, int *l, int *a) const
}
*h = ct.ahsl.hue == USHRT_MAX ? -1 : ct.ahsl.hue / 100;
- *s = ct.ahsl.saturation >> 8;
- *l = ct.ahsl.lightness >> 8;
+ *s = qt_div_257(ct.ahsl.saturation);
+ *l = qt_div_257(ct.ahsl.lightness);
if (a)
- *a = ct.ahsl.alpha >> 8;
+ *a = qt_div_257(ct.ahsl.alpha);
}
/*!
@@ -1181,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;
@@ -1194,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;
@@ -1248,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);
@@ -1296,16 +1294,16 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const
return;
}
- *r = ct.argb.red >> 8;
- *g = ct.argb.green >> 8;
- *b = ct.argb.blue >> 8;
+ *r = qt_div_257(ct.argb.red);
+ *g = qt_div_257(ct.argb.green);
+ *b = qt_div_257(ct.argb.blue);
if (a)
- *a = ct.argb.alpha >> 8;
+ *a = qt_div_257(ct.argb.alpha);
}
/*!
- \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).
@@ -1316,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);
@@ -1379,7 +1377,7 @@ QRgb QColor::rgba() const noexcept
{
if (cspec != Invalid && cspec != Rgb)
return toRgb().rgba();
- return qRgba(ct.argb.red >> 8, ct.argb.green >> 8, ct.argb.blue >> 8, ct.argb.alpha >> 8);
+ return qRgba(qt_div_257(ct.argb.red), qt_div_257(ct.argb.green), qt_div_257(ct.argb.blue), qt_div_257(ct.argb.alpha));
}
/*!
@@ -1442,7 +1440,7 @@ QRgb QColor::rgb() const noexcept
{
if (cspec != Invalid && cspec != Rgb)
return toRgb().rgb();
- return qRgb(ct.argb.red >> 8, ct.argb.green >> 8, ct.argb.blue >> 8);
+ return qRgb(qt_div_257(ct.argb.red), qt_div_257(ct.argb.green), qt_div_257(ct.argb.blue));
}
/*!
@@ -1468,8 +1466,8 @@ void QColor::setRgb(QRgb rgb) noexcept
int QColor::alpha() const noexcept
{
if (cspec == ExtendedRgb)
- return qRound(qreal(castF16(ct.argbExtended.alphaF16)) * 255);
- return ct.argb.alpha >> 8;
+ return qRound(float(castF16(ct.argbExtended.alphaF16)) * 255);
+ return qt_div_257(ct.argb.alpha);
}
@@ -1484,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;
@@ -1496,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);
}
@@ -1531,7 +1529,7 @@ int QColor::red() const noexcept
{
if (cspec != Invalid && cspec != Rgb)
return toRgb().red();
- return ct.argb.red >> 8;
+ return qt_div_257(ct.argb.red);
}
/*!
@@ -1558,7 +1556,7 @@ int QColor::green() const noexcept
{
if (cspec != Invalid && cspec != Rgb)
return toRgb().green();
- return ct.argb.green >> 8;
+ return qt_div_257(ct.argb.green);
}
/*!
@@ -1586,7 +1584,7 @@ int QColor::blue() const noexcept
{
if (cspec != Invalid && cspec != Rgb)
return toRgb().blue();
- return ct.argb.blue >> 8;
+ return qt_div_257(ct.argb.blue);
}
@@ -1610,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);
@@ -1627,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());
}
@@ -1642,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);
@@ -1659,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());
}
@@ -1674,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);
@@ -1689,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());
}
@@ -1747,7 +1745,7 @@ int QColor::hsvSaturation() const noexcept
{
if (cspec != Invalid && cspec != Hsv)
return toHsv().saturation();
- return ct.ahsv.saturation >> 8;
+ return qt_div_257(ct.ahsv.saturation);
}
/*!
@@ -1759,7 +1757,7 @@ int QColor::value() const noexcept
{
if (cspec != Invalid && cspec != Hsv)
return toHsv().value();
- return ct.ahsv.value >> 8;
+ return qt_div_257(ct.ahsv.value);
}
/*!
@@ -1769,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();
}
@@ -1780,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;
}
/*!
@@ -1795,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();
}
@@ -1805,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);
}
/*!
@@ -1817,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);
}
/*!
@@ -1849,7 +1847,7 @@ int QColor::hslSaturation() const noexcept
{
if (cspec != Invalid && cspec != Hsl)
return toHsl().hslSaturation();
- return ct.ahsl.saturation >> 8;
+ return qt_div_257(ct.ahsl.saturation);
}
/*!
@@ -1863,7 +1861,7 @@ int QColor::lightness() const noexcept
{
if (cspec != Invalid && cspec != Hsl)
return toHsl().lightness();
- return ct.ahsl.lightness >> 8;
+ return qt_div_257(ct.ahsl.lightness);
}
/*!
@@ -1873,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;
}
/*!
@@ -1887,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);
}
/*!
@@ -1901,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);
}
/*!
@@ -1917,7 +1915,7 @@ int QColor::cyan() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().cyan();
- return ct.acmyk.cyan >> 8;
+ return qt_div_257(ct.acmyk.cyan);
}
/*!
@@ -1929,7 +1927,7 @@ int QColor::magenta() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().magenta();
- return ct.acmyk.magenta >> 8;
+ return qt_div_257(ct.acmyk.magenta);
}
/*!
@@ -1941,7 +1939,7 @@ int QColor::yellow() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().yellow();
- return ct.acmyk.yellow >> 8;
+ return qt_div_257(ct.acmyk.yellow);
}
/*!
@@ -1954,7 +1952,7 @@ int QColor::black() const noexcept
{
if (cspec != Invalid && cspec != Cmyk)
return toCmyk().black();
- return ct.acmyk.black >> 8;
+ return qt_div_257(ct.acmyk.black);
}
/*!
@@ -1962,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);
}
/*!
@@ -1974,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);
}
/*!
@@ -1986,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);
}
/*!
@@ -1998,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);
}
/*!
@@ -2018,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);
@@ -2055,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:
@@ -2083,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:
@@ -2115,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);
}
@@ -2154,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;
@@ -2200,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
@@ -2213,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;
@@ -2251,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
@@ -2266,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;
@@ -2313,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);
@@ -2426,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);
@@ -2529,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();
}
@@ -2542,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;
@@ -2593,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();
}
@@ -2606,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);
@@ -2635,13 +2633,13 @@ void QColor::getCmyk(int *c, int *m, int *y, int *k, int *a) const
return;
}
- *c = ct.acmyk.cyan >> 8;
- *m = ct.acmyk.magenta >> 8;
- *y = ct.acmyk.yellow >> 8;
- *k = ct.acmyk.black >> 8;
+ *c = qt_div_257(ct.acmyk.cyan);
+ *m = qt_div_257(ct.acmyk.magenta);
+ *y = qt_div_257(ct.acmyk.yellow);
+ *k = qt_div_257(ct.acmyk.black);
if (a)
- *a = ct.acmyk.alpha >> 8;
+ *a = qt_div_257(ct.acmyk.alpha);
}
/*!
@@ -2654,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;
@@ -2664,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);
}
/*!
@@ -2711,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;
@@ -2772,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();
}
@@ -2870,28 +2868,6 @@ QColor QColor::darker(int factor) const noexcept
return hsv.convertTo(cspec);
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \obsolete
-
- Use lighter(\a factor) instead.
-*/
-QColor QColor::light(int factor) const noexcept
-{
- return lighter(factor);
-}
-
-/*!
- \obsolete
-
- Use darker(\a factor) instead.
-*/
-QColor QColor::dark(int factor) const noexcept
-{
- return darker(factor);
-}
-#endif
-
/*! \overload
Assigns a copy of \a color and returns a reference to this color.
*/
@@ -2901,26 +2877,27 @@ QColor &QColor::operator=(Qt::GlobalColor color) noexcept
}
/*!
- Returns \c true if this color has the same RGB and alpha values as \a color;
+ Returns \c true if this color has the same color specification and component values as \a color;
otherwise returns \c false.
+
+ ExtendedRgb and Rgb specifications are considered matching in this context.
+
+ \sa spec()
*/
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);
+ if ((cspec == ExtendedRgb || color.cspec == ExtendedRgb) &&
+ (cspec == color.cspec || cspec == Rgb || color.cspec == Rgb)) {
+ return qFuzzyCompare(alphaF(), color.alphaF())
+ && qFuzzyCompare(redF(), color.redF())
+ && qFuzzyCompare(greenF(), color.greenF())
+ && qFuzzyCompare(blueF(), color.blueF());
} 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);
@@ -2928,8 +2905,12 @@ bool QColor::operator==(const QColor &color) const noexcept
}
/*!
- Returns \c true if this color has a different RGB and alpha values from
+ Returns \c true if this color has different color specification or component values from
\a color; otherwise returns \c false.
+
+ ExtendedRgb and Rgb specifications are considered matching in this context.
+
+ \sa spec()
*/
bool QColor::operator!=(const QColor &color) const noexcept
{ return !operator==(color); }
@@ -2940,7 +2921,7 @@ bool QColor::operator!=(const QColor &color) const noexcept
*/
QColor::operator QVariant() const
{
- return QVariant(QVariant::Color, this);
+ return QVariant::fromValue(*this);
}
/*! \internal
@@ -3146,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()
*/
/*!
@@ -3155,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()
*/
/*!
@@ -3218,12 +3199,17 @@ 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()
*/
/*!
\namespace QColorConstants
\inmodule QtGui
+ \since 5.14
\brief The QColorConstants namespace contains QColor predefined constants.
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index 423a0ac50f..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,40 +30,45 @@ 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(cspec == Rgb ? a * 0x0101 : 0,
- cspec == Rgb ? r * 0x0101 : 0,
- cspec == Rgb ? g * 0x0101 : 0,
- cspec == Rgb ? b * 0x0101 : 0,
+ ct(ushort(cspec == Rgb ? a * 0x0101 : 0),
+ ushort(cspec == Rgb ? r * 0x0101 : 0),
+ ushort(cspec == Rgb ? g * 0x0101 : 0),
+ ushort(cspec == Rgb ? b * 0x0101 : 0),
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,53 +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);
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use QColor::lighter() instead")
- Q_REQUIRED_RESULT QColor light(int f = 150) const noexcept;
- QT_DEPRECATED_X("Use QColor::darker() instead")
- Q_REQUIRED_RESULT QColor dark(int f = 200) const noexcept;
-#endif
- 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;
}
@@ -250,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 {
@@ -299,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 edb2d32258..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,28 +56,151 @@ 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 QMatrix because only floats are needed and performance is critical.
+// Not using QTransform because only floats are needed and performance is critical.
class QColorMatrix
{
public:
@@ -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 9631fdb416..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,35 +553,71 @@ 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.
*/
QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
{
- static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
- if (!predefinedColorspacePrivates[namedColorSpace]) {
- predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
- predefinedColorspacePrivates[namedColorSpace]->ref.ref();
+ if (namedColorSpace < QColorSpace::SRgb || namedColorSpace > QColorSpace::ProPhotoRgb) {
+ qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace);
+ return;
+ }
+ // 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();
}
/*!
@@ -449,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
@@ -545,12 +771,19 @@ float QColorSpace::gamma() const noexcept
*/
void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunction, float gamma)
{
- if (!isValid() || transferFunction == QColorSpace::TransferFunction::Custom)
+ if (transferFunction == TransferFunction::Custom)
return;
+ if (!d_ptr) {
+ d_ptr = new QColorSpacePrivate(Primaries::Custom, transferFunction, gamma);
+ 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();
@@ -558,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.
@@ -565,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;
@@ -575,19 +863,62 @@ 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()
*/
void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
{
- if (!isValid() || primariesId == QColorSpace::Primaries::Custom)
+ if (primariesId == Primaries::Custom)
+ return;
+ if (!d_ptr) {
+ d_ptr = new QColorSpacePrivate(primariesId, TransferFunction::Custom, 0.0f);
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();
}
@@ -601,23 +932,119 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint)
{
- if (!isValid())
- return;
QColorSpacePrimaries primaries(whitePoint, redPoint, greenPoint, bluePoint);
if (!primaries.areValid())
return;
+ if (!d_ptr) {
+ d_ptr = new QColorSpacePrivate(primaries, TransferFunction::Custom, 0.0f);
+ 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
@@ -644,7 +1071,7 @@ 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().
@@ -656,88 +1083,271 @@ 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)
+{
+ 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 (colorSpace1.d_ptr == colorSpace2.d_ptr)
+ 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());
+}
- if (colorSpace1.d_ptr->namedColorSpace && colorSpace2.d_ptr->namedColorSpace)
- return colorSpace1.d_ptr->namedColorSpace == colorSpace2.d_ptr->namedColorSpace;
+/*!
+ \internal
+*/
+bool QColorSpacePrivate::equals(const QColorSpacePrivate *other) const
+{
+ if (!other)
+ return false;
+
+ if (namedColorSpace && other->namedColorSpace)
+ return namedColorSpace == other->namedColorSpace;
- const bool valid1 = colorSpace1.isValid();
- const bool valid2 = colorSpace2.isValid();
- if (!valid1 && !valid2)
- return colorSpace1.d_ptr->iccProfile == colorSpace2.d_ptr->iccProfile;
- else if (!valid1 || !valid2)
+ const bool valid1 = isValid();
+ const bool valid2 = other->isValid();
+ if (valid1 != valid2)
+ return false;
+ if (!valid1 && !valid2) {
+ 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
- // At this point one or both color spaces are unknown but valid, and must be compared in detail instead
+ if (transformModel != other->transformModel)
+ return false;
- if (colorSpace1.primaries() != QColorSpace::Primaries::Custom && colorSpace2.primaries() != QColorSpace::Primaries::Custom) {
- if (colorSpace1.primaries() != colorSpace2.primaries())
+ 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();
+
+ 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);
+ return d_ptr->transformationToColorSpace(colorspace.d_ptr.get());
+}
+
+/*!
+ Returns the color space as a QVariant.
+ \since 5.15
+*/
+QColorSpace::operator QVariant() const
+{
+ 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;
}
/*****************************************************************************
@@ -779,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);
@@ -787,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;
@@ -796,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 e6bc62d58a..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
@@ -44,12 +8,15 @@
#include <QtGui/qcolortransform.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qshareddata.h>
+#include <QtCore/qvariant.h>
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
@@ -78,69 +45,106 @@ 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;
QColorTransform transformationToColorSpace(const QColorSpace &colorspace) const;
+ 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 c8b2f7bd92..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
@@ -54,7 +18,9 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "qcolortransferfunction_p.h"
-#include <QVector>
+#include <QList>
+
+#include <algorithm>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -63,54 +29,85 @@ QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QColorTransferTable
{
public:
- QColorTransferTable() noexcept
- : m_tableSize(0)
- { }
- QColorTransferTable(uint32_t size, const QVector<uint8_t> &table) noexcept
- : m_tableSize(size)
- , m_table8(table)
- { }
- QColorTransferTable(uint32_t size, const QVector<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;
}
@@ -118,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))
@@ -207,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;
- QVector<uint8_t> m_table8;
- QVector<uint16_t> m_table16;
+ 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 e2497eaadb..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"
@@ -47,6 +11,8 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qoperatingsystemversion.h>
+QT_USE_NAMESPACE
+
QT_BEGIN_NAMESPACE
// ---------------------- Images ----------------------
@@ -56,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;
}
@@ -124,49 +90,81 @@ QImage qt_mac_toQImage(CGImageRef image)
#ifdef Q_OS_MACOS
-static NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image)
+QT_END_NAMESPACE
+
+@implementation NSImage (QtExtras)
++ (instancetype)imageFromQImage:(const QImage &)image
{
- NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize];
- return newImage;
+ if (image.isNull())
+ return nil;
+
+ QCFType<CGImageRef> cgImage = image.toCGImage();
+ if (!cgImage)
+ return nil;
+
+ // We set up the NSImage using an explicit NSBitmapImageRep, instead of
+ // [NSImage initWithCGImage:size:], as the former allows us to correctly
+ // set the size of the representation to account for the device pixel
+ // ratio of the original image, which in turn will be reflected by the
+ // NSImage.
+ auto nsImage = [[NSImage alloc] initWithSize:NSZeroSize];
+ auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
+ imageRep.size = image.deviceIndependentSize().toCGSize();
+ [nsImage addRepresentation:[imageRep autorelease]];
+ Q_ASSERT(CGSizeEqualToSize(nsImage.size, imageRep.size));
+
+ return [nsImage autorelease];
}
-NSImage *qt_mac_create_nsimage(const QPixmap &pm)
++ (instancetype)imageFromQIcon:(const QIcon &)icon
{
- if (pm.isNull())
- return 0;
- QImage image = pm.toImage();
- CGImageRef cgImage = qt_mac_toCGImage(image);
- NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage);
- nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize();
- CGImageRelease(cgImage);
- return nsImage;
+ return [NSImage imageFromQIcon:icon withSize:0];
}
-NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize)
++ (instancetype)imageFromQIcon:(const QIcon &)icon withSize:(int)size
{
if (icon.isNull())
return nil;
- NSImage *nsImage = [[NSImage alloc] init];
- QList<QSize> availableSizes = icon.availableSizes();
- if (availableSizes.isEmpty() && defaultSize > 0)
- availableSizes << QSize(defaultSize, defaultSize);
- for (QSize size : qAsConst(availableSizes)) {
- QPixmap pm = icon.pixmap(size);
- if (pm.isNull())
+ auto availableSizes = icon.availableSizes();
+ if (availableSizes.isEmpty() && size > 0)
+ availableSizes << QSize(size, size);
+
+ auto nsImage = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease];
+
+ for (QSize size : std::as_const(availableSizes)) {
+ QImage image = icon.pixmap(size).toImage();
+ if (image.isNull())
continue;
- QImage image = pm.toImage();
- CGImageRef cgImage = qt_mac_toCGImage(image);
- NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
- [nsImage addRepresentation:imageRep];
- [imageRep release];
- CGImageRelease(cgImage);
+
+ QCFType<CGImageRef> cgImage = image.toCGImage();
+ if (!cgImage)
+ continue;
+
+ auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
+ imageRep.size = image.deviceIndependentSize().toCGSize();
+ [nsImage addRepresentation:[imageRep autorelease]];
}
+
+ if (!nsImage.representations.count)
+ return nil;
+
+ [nsImage setTemplate:icon.isMask()];
+
+ if (size)
+ nsImage.size = CGSizeMake(size, size);
+
return nsImage;
}
+@end
+
+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);
@@ -187,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)
@@ -212,18 +229,33 @@ QColor qt_mac_toQColor(CGColorRef color)
QColor qt_mac_toQColor(const NSColor *color)
{
QColor qtColor;
- NSString *colorSpace = [color colorSpaceName];
- if (colorSpace == NSDeviceCMYKColorSpace) {
- CGFloat cyan, magenta, yellow, black, alpha;
- [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
- qtColor.setCmykF(cyan, magenta, yellow, black, alpha);
- } else {
- NSColor *tmpColor;
- tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- CGFloat red, green, blue, alpha;
+ switch (color.type) {
+ case NSColorTypeComponentBased: {
+ const NSColorSpace *colorSpace = [color colorSpace];
+ if (colorSpace == NSColorSpace.genericRGBColorSpace
+ && color.numberOfComponents == 4) { // rbga
+ CGFloat components[4];
+ [color getComponents:components];
+ qtColor.setRgbF(components[0], components[1], components[2], components[3]);
+ break;
+ } else if (colorSpace == NSColorSpace.genericCMYKColorSpace
+ && color.numberOfComponents == 5) { // cmyk + alpha
+ CGFloat components[5];
+ [color getComponents:components];
+ qtColor.setCmykF(components[0], components[1], components[2], components[3], components[4]);
+ break;
+ }
+ }
+ Q_FALLTHROUGH();
+ default: {
+ const NSColor *tmpColor = [color colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
[tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
qtColor.setRgbF(red, green, blue, alpha);
+ break;
+ }
}
+
return qtColor;
}
#endif
@@ -249,9 +281,9 @@ static bool qt_mac_isSystemColorOrInstance(const NSColor *color, NSString *color
// We specifically do not want isKindOfClass: here
if ([color.className isEqualToString:className]) // NSPatternColorSpace
return true;
- if ([color.catalogNameComponent isEqualToString:@"System"] &&
- [color.colorNameComponent isEqualToString:colorNameComponent] &&
- [color.colorSpaceName isEqualToString:NSNamedColorSpace])
+ if (color.type == NSColorTypeCatalog &&
+ [color.catalogNameComponent isEqualToString:@"System"] &&
+ [color.colorNameComponent isEqualToString:colorNameComponent])
return true;
return false;
}
@@ -307,8 +339,8 @@ QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup)
return qtBrush;
}
- if (NSColor *patternColor = [color colorUsingColorSpaceName:NSPatternColorSpace]) {
- NSImage *patternImage = patternColor.patternImage;
+ if (color.type == NSColorTypePattern) {
+ NSImage *patternImage = color.patternImage;
const QSizeF sz(patternImage.size.width, patternImage.size.height);
// FIXME: QBrush is not resolution independent (QTBUG-49774)
qtBrush.setTexture(qt_mac_toQPixmap(patternImage, sz));
@@ -376,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:
@@ -464,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 ba2cde8325..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,38 @@
#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
-Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QPixmap &pm);
-Q_GUI_EXPORT NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize = 0);
+#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;
++ (instancetype)imageFromQIcon:(const QT_PREPEND_NAMESPACE(QIcon) &)icon withSize:(int)size;
+@end
+QT_BEGIN_NAMESPACE
+
#endif
Q_GUI_EXPORT CGImageRef qt_mac_toCGImage(const QImage &qImage);
Q_GUI_EXPORT CGImageRef qt_mac_toCGImageMask(const QImage &qImage);
@@ -81,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
@@ -105,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 bece814a6f..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,16 +341,17 @@ 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;
stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
@@ -387,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;
}
@@ -400,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;
}
@@ -423,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);
@@ -440,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;
@@ -472,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;
@@ -691,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) {
@@ -714,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;
@@ -737,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);
@@ -762,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;
@@ -852,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;
@@ -949,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) {
@@ -959,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);
@@ -983,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);
}
@@ -993,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);
}
@@ -1003,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);
}
@@ -1012,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) {
@@ -1022,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);
@@ -1046,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);
}
@@ -1057,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);
}
@@ -1067,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 181d19da0b..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,30 +72,33 @@ 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;
while (capacity < size)
capacity *= 2;
- buffer = (Type*) realloc(buffer, capacity * sizeof(Type));
+ buffer = (Type*) realloc(static_cast<void*>(buffer), capacity * sizeof(Type));
Q_CHECK_PTR(buffer);
}
}
- inline void shrink(int size) {
+ void shrink(qsizetype size) {
+ Q_ASSERT(capacity >= size);
capacity = size;
if (size) {
- buffer = (Type*) realloc(buffer, capacity * sizeof(Type));
+ 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 6819545bda..b7a943be38 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -1,52 +1,15 @@
-/****************************************************************************
-**
-** 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/qpaintengine_raster_p.h>
-#include <private/qpainter_p.h>
#include <private/qdrawhelper_x86_p.h>
#include <private/qdrawingprimitive_sse2_p.h>
#include <private/qdrawhelper_neon_p.h>
@@ -54,11 +17,24 @@
#include <private/qdrawhelper_mips_dsp_p.h>
#endif
#include <private/qguiapplication_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <private/qpainter_p.h>
+#include <private/qpixellayout_p.h>
#include <private/qrgba64_p.h>
#include <qendian.h>
#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")
@@ -69,1592 +45,264 @@ Q_LOGGING_CATEGORY(lcQtGuiDrawHelper, "qt.gui.drawhelper")
constants and structures
*/
-enum {
- fixed_scale = 1 << 16,
- half_point = 1 << 15
-};
-
-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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#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; }
-#endif
-
-template<QImage::Format> constexpr QPixelLayout::BPP bitsPerPixel();
-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; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
-template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
-
-
-typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count);
+constexpr int fixed_scale = 1 << 16;
+constexpr int half_point = 1 << 15;
template <QPixelLayout::BPP bpp> static
-uint QT_FASTCALL fetchPixel(const uchar *, int)
+inline uint QT_FASTCALL fetch1Pixel(const uchar *, int)
{
- Q_UNREACHABLE();
- return 0;
+ Q_UNREACHABLE_RETURN(0);
}
template <>
-inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+inline uint QT_FASTCALL fetch1Pixel<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)
+inline uint QT_FASTCALL fetch1Pixel<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)
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP8>(const uchar *src, int index)
{
return src[index];
}
template <>
-inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
+inline uint QT_FASTCALL fetch1Pixel<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)
+inline uint QT_FASTCALL fetch1Pixel<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)
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32>(const uchar *src, int index)
{
return reinterpret_cast<const uint *>(src)[index];
}
template <>
-inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP64>(const uchar *src, int index)
+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 <QPixelLayout::BPP bpp>
-static quint64 QT_FASTCALL fetchPixel64(const uchar *src, int index)
-{
- Q_STATIC_ASSERT(bpp != QPixelLayout::BPP64);
- return fetchPixel<bpp>(src, index);
-}
-
-template <QPixelLayout::BPP width> static
-void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel);
-
template <>
-inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP16FPx4>(const uchar *src, int index)
{
- reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
+ // 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 void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
+inline uint QT_FASTCALL fetch1Pixel<QPixelLayout::BPP32FPx4>(const uchar *src, int index)
{
- reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
+ // 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 *FetchPixelFunc)(const uchar *src, int index);
+typedef uint (QT_FASTCALL *Fetch1PixelFunc)(const uchar *src, int index);
-static const FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = {
+constexpr Fetch1PixelFunc fetch1PixelTable[QPixelLayout::BPPCount] = {
nullptr, // BPPNone
- fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB
- fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB
- fetchPixel<QPixelLayout::BPP8>, // BPP8
- fetchPixel<QPixelLayout::BPP16>, // BPP16
- fetchPixel<QPixelLayout::BPP24>, // BPP24
- fetchPixel<QPixelLayout::BPP32>, // BPP32
- fetchPixel<QPixelLayout::BPP64> // BPP64
+ 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>,
};
-template<QImage::Format Format>
-static Q_ALWAYS_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);
-
- Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>();
- Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>();
- Q_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;
-
- uint red = (s >> redShift<Format>()) & redMask;
- uint green = (s >> greenShift<Format>()) & greenMask;
- uint blue = (s >> blueShift<Format>()) & blueMask;
-
- red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
- green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
- blue = (blue << blueLeftShift) | (blue >> blueRightShift);
- return 0xff000000 | red | green | blue;
-}
-
-template<QImage::Format Format>
-static void QT_FASTCALL convertToRGB32(uint *buffer, int count, const QVector<QRgb> *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB32<Format>(buffer[i]);
-}
-
-#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
-extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count);
-#endif
-
-template<QImage::Format Format>
-static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
-#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
- if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
- // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
- // to vectorize the deforested version below.
- fetchPixelsBPP24_ssse3(buffer, src, index, count);
- convertToRGB32<Format>(buffer, count, nullptr);
- return buffer;
- }
-#endif
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
- return buffer;
-}
-
-template<QImage::Format Format>
-static Q_ALWAYS_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 *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB64<Format>(src[i]);
- return buffer;
-}
-
-template<QImage::Format Format>
-static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<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 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);
-
- 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>();
-
- 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;
-
- Q_CONSTEXPR bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
- (alphaWidth<Format>() != greenWidth<Format>()) ||
- (alphaWidth<Format>() != blueWidth<Format>());
-
- uint alpha = (s >> alphaShift<Format>()) & alphaMask;
- uint red = (s >> redShift<Format>()) & redMask;
- uint green = (s >> greenShift<Format>()) & greenMask;
- uint blue = (s >> blueShift<Format>()) & blueMask;
-
- alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
- red = (red << redLeftShift) | (red >> redRightShift);
- green = (green << greenLeftShift) | (green >> greenRightShift);
- blue = (blue << blueLeftShift) | (blue >> blueRightShift);
-
- if (mustMin) {
- red = qMin(alpha, red);
- green = qMin(alpha, green);
- blue = qMin(alpha, blue);
- }
-
- return (alpha << 24) | (red << 16) | (green << 8) | blue;
-}
-
-template<QImage::Format Format>
-static void QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, int count, const QVector<QRgb> *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToARGB32PM<Format>(buffer[i]);
-}
-
-template<QImage::Format Format>
-static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
-#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
- if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
- // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
- // to vectorize the deforested version below.
- fetchPixelsBPP24_ssse3(buffer, src, index, count);
- convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
- return buffer;
- }
-#endif
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
- return buffer;
-}
-
-template<QImage::Format Format>
-static Q_ALWAYS_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 *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGB64<Format>(src[i]);
- return buffer;
-}
-
-template<QImage::Format Format>
-static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+#if QT_CONFIG(raster_64bit)
+static void QT_FASTCALL convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
{
- constexpr QPixelLayout::BPP bpp = bitsPerPixel<Format>();
for (int i = 0; i < count; ++i)
- buffer[i] = convertPixelToRGBA64PM<Format>(fetchPixel<bpp>(src, index + i));
- 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)
-{
- Q_CONSTEXPR uchar rWidth = redWidth<Format>();
- Q_CONSTEXPR uchar gWidth = greenWidth<Format>();
- Q_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>();
-
- for (int i = 0; i < count; ++i) {
- const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
- const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
- const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
- const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
- storePixel<BPP>(dest, index + i, r | g | b);
- };
- } else {
- // We do ordered dither by using a rounding conversion, but instead of
- // adding half of input precision, we add the adjusted result from the
- // bayer matrix before narrowing.
- // Note: Rounding conversion in itself is different from the naive
- // conversion we do above for non-dithering.
- const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
- for (int i = 0; i < count; ++i) {
- const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
- const int d = bayer_line[(dither->x + i) & 15];
- const int dr = d - ((d + 1) >> rWidth);
- const int dg = d - ((d + 1) >> gWidth);
- const int db = d - ((d + 1) >> bWidth);
- int r = qRed(c);
- int g = qGreen(c);
- int b = qBlue(c);
- r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
- g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
- b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
- const uint s = (r << redShift<Format>())
- | (g << greenShift<Format>())
- | (b << blueShift<Format>());
- storePixel<BPP>(dest, index + i, s);
- }
- }
-}
-
-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)
-{
- 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;
-
- 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>();
-
- Q_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>());
- const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
- const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
- const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
- 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>();
-
- const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
- for (int i = 0; i < count; ++i) {
- const uint c = src[i];
- const int d = bayer_line[(dither->x + i) & 15];
- const int da = d - ((d + 1) >> aWidth);
- const int dr = d - ((d + 1) >> rWidth);
- const int dg = d - ((d + 1) >> gWidth);
- const int db = d - ((d + 1) >> bWidth);
- int a = qAlpha(c);
- int r = qRed(c);
- int g = qGreen(c);
- int b = qBlue(c);
- if (fromRGB)
- a = (1 << aWidth) - 1;
- else
- a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth);
- r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
- g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
- b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
- uint s = (a << alphaShift<Format>())
- | (r << redShift<Format>())
- | (g << greenShift<Format>())
- | (b << blueShift<Format>());
- storePixel<BPP>(dest, index + i, s);
- }
- }
-}
-
-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
- Q_STATIC_ASSERT(rWidth == bWidth);
-#endif
- Q_CONSTEXPR uint redBlueMask = (1 << rWidth) - 1;
- Q_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 = fetchPixel<bpp>(src, i);
- const uint r = (c >> rShift) & redBlueMask;
- const uint b = (c >> bShift) & redBlueMask;
- const uint t = (c & alphaGreenMask)
- | (r << bShift)
- | (b << rShift);
- storePixel<bpp>(dst, i, t);
- }
-}
-
-static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count)
-{
- const uint *src = reinterpret_cast<const uint *>(s);
- uint *dest = reinterpret_cast<uint *>(d);
- for (int i = 0; i < count; ++i) {
- const uint c = src[i];
- const uint ag = c & 0xff00ff00;
- const uint rb = c & 0x00ff00ff;
- dest[i] = ag | (rb << 16) | (rb >> 16);
- }
-}
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template<>
-void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
-{
- return rbSwap_rgb32(d, s, count);
-}
-#else
-template<>
-void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
-{
- const uint *src = reinterpret_cast<const uint *>(s);
- uint *dest = reinterpret_cast<uint *>(d);
- for (int i = 0; i < count; ++i) {
- const uint c = src[i];
- const uint rb = c & 0xff00ff00;
- const uint ga = c & 0x00ff00ff;
- dest[i] = ga | (rb << 16) | (rb >> 16);
- }
-}
-#endif
-
-static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
-{
- const uint *src = reinterpret_cast<const uint *>(s);
- uint *dest = reinterpret_cast<uint *>(d);
- UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
-}
-
-template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
-{
- return QPixelLayout{
- false,
- false,
- bitsPerPixel<Format>(),
- rbSwap<Format>,
- convertToRGB32<Format>,
- convertToRGB64<Format>,
- fetchRGBToRGB32<Format>,
- fetchRGBToRGB64<Format>,
- storeRGBFromARGB32PM<Format, false>,
- storeRGBFromARGB32PM<Format, true>
- };
-}
-
-template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM()
-{
- return QPixelLayout{
- true,
- true,
- bitsPerPixel<Format>(),
- rbSwap<Format>,
- convertARGBPMToARGB32PM<Format>,
- convertARGBPMToRGBA64PM<Format>,
- fetchARGBPMToARGB32PM<Format>,
- fetchARGBPMToRGBA64PM<Format>,
- storeARGBPMFromARGB32PM<Format, false>,
- storeARGBPMFromARGB32PM<Format, true>
- };
+ buffer[i] = buffer[i].premultiplied();
}
-static void QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, int count, const QVector<QRgb> *clut)
+static void QT_FASTCALL convertRGBA64PMToRGBA64PM(QRgba64 *, int)
{
- for (int i = 0; i < count; ++i)
- buffer[i] = qPremultiply(clut->at(buffer[i]));
}
-template<QPixelLayout::BPP BPP>
-static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
+static void QT_FASTCALL convertRGBA16FToRGBA64PM(QRgba64 *buffer, int count)
{
+ const QRgbaFloat16 *in = reinterpret_cast<const QRgbaFloat16 *>(buffer);
for (int i = 0; i < count; ++i) {
- const uint s = fetchPixel<BPP>(src, index + i);
- buffer[i] = qPremultiply(clut->at(s));
+ QRgbaFloat16 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
}
- return buffer;
}
-template<QPixelLayout::BPP BPP>
-static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
+static void QT_FASTCALL convertRGBA16FPMToRGBA64PM(QRgba64 *buffer, int count)
{
+ const QRgbaFloat16 *in = reinterpret_cast<const QRgbaFloat16 *>(buffer);
for (int i = 0; i < count; ++i) {
- const uint s = fetchPixel<BPP>(src, index + i);
- buffer[i] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
+ QRgbaFloat16 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL convertIndexedToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *clut, QDitherInfo *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(clut->at(src[i])).premultiplied();
- return buffer;
-}
-
-static void QT_FASTCALL convertPassThrough(uint *, int, const QVector<QRgb> *)
-{
-}
-
-static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
- const QVector<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 *)
-{
- 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 *)
-{
- 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> *)
-{
- qt_convertARGB32ToARGB32PM(buffer, buffer, count);
-}
-
-static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<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> *)
-{
- 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 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> *)
-{
- qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
-}
-
-static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<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> *)
-{
- 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 *)
-{
- 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 *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::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 *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::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 convertRGBA32FToRGBA64PM(QRgba64 *buffer, int count)
{
+ const QRgbaFloat32 *in = reinterpret_cast<const QRgbaFloat32 *>(buffer);
for (int i = 0; i < count; ++i) {
- const uint s = buffer[i];
- buffer[i] = qRgb(s, s, s);
+ QRgbaFloat32 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16()).premultiplied();
}
}
-static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static void QT_FASTCALL convertRGBA32FPMToRGBA64PM(QRgba64 *buffer, int count)
{
+ const QRgbaFloat32 *in = reinterpret_cast<const QRgbaFloat32 *>(buffer);
for (int i = 0; i < count; ++i) {
- const uint s = src[index + i];
- buffer[i] = qRgb(s, s, s);
+ QRgbaFloat32 c = in[i];
+ buffer[i] = QRgba64::fromRgba64(c.red16(), c.green16(), c.blue16(), c.alpha16());
}
- return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::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 *)
-{
- for (int i = 0; i < count; ++i) {
- const uint s = src[index + i];
- buffer[i] = QRgba64::fromRgba(s, s, s, 255);
- }
- return buffer;
-}
+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 void QT_FASTCALL convertGrayscale16ToRGB32(uint *buffer, int count, const QVector<QRgb> *)
-{
- for (int i = 0; i < count; ++i) {
- const uint x = qt_div_257(buffer[i]);
- buffer[i] = qRgb(x, x, x);
- }
-}
+static_assert(std::size(convert64ToRGBA64PM) == QImage::NImageFormats);
+#endif
-static const uint *QT_FASTCALL fetchGrayscale16ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+#if QT_CONFIG(raster_fp)
+static void QT_FASTCALL convertRGBA64PMToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
{
- const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
for (int i = 0; i < count; ++i) {
- const uint x = qt_div_257(s[i]);
- buffer[i] = qRgb(x, x, x);
+ auto c = in[i];
+ buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), c.alpha()).premultiplied();
}
- return buffer;
}
-static const QRgba64 *QT_FASTCALL convertGrayscale16ToRGBA64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static void QT_FASTCALL convertRGBA64ToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
{
- 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);
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchGrayscale16ToRGBA64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
+ const auto *in = reinterpret_cast<const QRgba64 *>(src);
for (int i = 0; i < count; ++i) {
- buffer[i] = QRgba64::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 *)
-{
- 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 *)
-{
- uint *d = reinterpret_cast<uint *>(dest) + index;
- UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
-}
-
-#ifdef __SSE2__
-template<bool RGBA, bool maskAlpha>
-static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
-{
- if (count <= 0)
- return;
-
- const __m128i amask = _mm_set1_epi32(0xff000000);
- int i = 0;
- for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
- uint s = *src++;
- if (maskAlpha)
- s = s | 0xff000000;
- if (RGBA)
- s = RGBA2ARGB(s);
- *buffer++ = QRgba64::fromArgb32(s);
- }
- for (; i < count-3; i += 4) {
- __m128i vs = _mm_loadu_si128((const __m128i*)src);
- if (maskAlpha)
- vs = _mm_or_si128(vs, amask);
- src += 4;
- __m128i v1 = _mm_unpacklo_epi8(vs, vs);
- __m128i v2 = _mm_unpackhi_epi8(vs, vs);
- if (!RGBA) {
- v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
- v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
- v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
- v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
- }
- _mm_store_si128((__m128i*)(buffer), v1);
- buffer += 2;
- _mm_store_si128((__m128i*)(buffer), v2);
- buffer += 2;
- }
-
- SIMD_EPILOGUE(i, count, 3) {
- uint s = *src++;
- if (maskAlpha)
- s = s | 0xff000000;
- if (RGBA)
- s = RGBA2ARGB(s);
- *buffer++ = QRgba64::fromArgb32(s);
+ auto c = in[i];
+ buffer[i] = QRgbaFloat32::fromRgba64(c.red(), c.green(), c.blue(), c.alpha());
}
}
-template<QtPixelOrder PixelOrder>
-static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count)
-{
- const __m128i gmask = _mm_set1_epi32(0x000ffc00);
- const __m128i cmask = _mm_set1_epi32(0x000003ff);
- int i = 0;
- __m128i vr, vg, vb, va;
- for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
- *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
- }
-
- for (; i < count-15; i += 16) {
- // Repremultiplying is really expensive and hard to do in SIMD without AVX2,
- // so we try to avoid it by checking if it is needed 16 samples at a time.
- __m128i vOr = _mm_set1_epi32(0);
- __m128i vAnd = _mm_set1_epi32(0xffffffff);
- for (int j = 0; j < 16; j += 2) {
- __m128i vs = _mm_load_si128((const __m128i*)(buffer + j));
- vOr = _mm_or_si128(vOr, vs);
- vAnd = _mm_and_si128(vAnd, vs);
- }
- const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7));
- const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7));
-
- if (andAlpha == 0xffff) {
- for (int j = 0; j < 16; j += 2) {
- __m128i vs = _mm_load_si128((const __m128i*)buffer);
- buffer += 2;
- vr = _mm_srli_epi64(vs, 6);
- vg = _mm_srli_epi64(vs, 16 + 6 - 10);
- vb = _mm_srli_epi64(vs, 32 + 6);
- vr = _mm_and_si128(vr, cmask);
- vg = _mm_and_si128(vg, gmask);
- vb = _mm_and_si128(vb, cmask);
- va = _mm_srli_epi64(vs, 48 + 14);
- if (PixelOrder == PixelOrderRGB)
- vr = _mm_slli_epi32(vr, 20);
- else
- vb = _mm_slli_epi32(vb, 20);
- va = _mm_slli_epi32(va, 30);
- __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va));
- vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0));
- _mm_storel_epi64((__m128i*)dest, vd);
- dest += 2;
- }
- } else if (orAlpha == 0) {
- for (int j = 0; j < 16; ++j) {
- *dest++ = 0;
- buffer++;
- }
- } else {
- for (int j = 0; j < 16; ++j)
- *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
- }
- }
-
- SIMD_EPILOGUE(i, count, 15)
- *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
-}
-#elif defined(__ARM_NEON__)
-template<bool RGBA, bool maskAlpha>
-static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
-{
- if (count <= 0)
- return;
-
- const uint32x4_t amask = vdupq_n_u32(0xff000000);
-#if defined(Q_PROCESSOR_ARM_64)
- const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
-#else
- const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 };
-#endif
- int i = 0;
- for (; i < count-3; i += 4) {
- uint32x4_t vs32 = vld1q_u32(src);
- src += 4;
- if (maskAlpha)
- vs32 = vorrq_u32(vs32, amask);
- uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
- if (!RGBA) {
-#if defined(Q_PROCESSOR_ARM_64)
- vs8 = vqtbl1q_u8(vs8, rgbaMask);
-#else
- // no vqtbl1q_u8
- const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
- const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
- vs8 = vcombine_u8(vlo, vhi);
-#endif
- }
- uint8x16x2_t v = vzipq_u8(vs8, vs8);
-
- vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
- buffer += 2;
- vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
- buffer += 2;
- }
-
- SIMD_EPILOGUE(i, count, 3) {
- uint s = *src++;
- if (maskAlpha)
- s = s | 0xff000000;
- if (RGBA)
- s = RGBA2ARGB(s);
- *buffer++ = QRgba64::fromArgb32(s);
- }
-}
-#endif
-
-static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
-#ifdef __SSE2__
- qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
-#elif defined(__ARM_NEON__)
- qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
-#else
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
-#endif
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<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 *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<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 *)
-{
-#ifdef __SSE2__
- qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
-#elif defined(__ARM_NEON__)
- qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
-#else
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(src[i]);
-#endif
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- return convertARGB32PMToRGBA64PM(buffer, reinterpret_cast<const uint *>(src) + index, count, nullptr, nullptr);
-}
-
-#if QT_CONFIG(raster_64bit)
-static void convertRGBA64ToRGBA64PM(QRgba64 *buffer, int count)
+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 convertRGBA64PMToRGBA64PM(QRgba64 *, int)
-{
-}
-#endif
-
-static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromRgba64(s[i]).premultiplied();
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL convertRGBA8888ToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<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 *)
-{
-#ifdef __SSE2__
- qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
-#elif defined(__ARM_NEON__)
- qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
-#else
- for (int i = 0; i < count; ++i)
- buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
-#endif
- return buffer;
-}
-
-static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<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 *)
-{
- 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 *)
-{
- 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 *)
-{
- 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> *)
-{
- for (int i = 0; i < count; ++i)
- buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
-}
-
-template<QtPixelOrder PixelOrder>
-static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
- const QVector<QRgb> *, QDitherInfo *dither)
-{
- const uint *src = reinterpret_cast<const uint *>(s) + index;
- if (!dither) {
- UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>);
- } else {
- for (int i = 0; i < count; ++i) {
- const uint c = src[i];
- short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2);
- short a10 = (c >> 30) * 0x155;
- short r10 = ((c >> 20) & 0x3ff);
- short g10 = ((c >> 10) & 0x3ff);
- short b10 = (c & 0x3ff);
- if (PixelOrder == PixelOrderBGR)
- std::swap(r10, b10);
- short a8 = (a10 + ((d10 - a10) >> 8)) >> 2;
- short r8 = (r10 + ((d10 - r10) >> 8)) >> 2;
- short g8 = (g10 + ((d10 - g10) >> 8)) >> 2;
- short b8 = (b10 + ((d10 - b10) >> 8)) >> 2;
- buffer[i] = qRgba(r8, g8, b8, a8);
- }
- }
- return buffer;
-}
-
-#ifdef __SSE2__
-template<QtPixelOrder PixelOrder>
-static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
-{
- if (count <= 0)
- return;
-
- const __m128i rmask = _mm_set1_epi32(0x3ff00000);
- const __m128i gmask = _mm_set1_epi32(0x000ffc00);
- const __m128i bmask = _mm_set1_epi32(0x000003ff);
- const __m128i afactor = _mm_set1_epi16(0x5555);
- int i = 0;
-
- for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
- *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
-
- for (; i < count-3; i += 4) {
- __m128i vs = _mm_loadu_si128((const __m128i*)src);
- src += 4;
- __m128i va = _mm_srli_epi32(vs, 30);
- __m128i vr = _mm_and_si128(vs, rmask);
- __m128i vb = _mm_and_si128(vs, bmask);
- __m128i vg = _mm_and_si128(vs, gmask);
- va = _mm_mullo_epi16(va, afactor);
- vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24));
- vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14));
- vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4));
- __m128i vrb;
- if (PixelOrder == PixelOrderRGB)
- vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2));
- else
- vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2));
- __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2));
- _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga));
- buffer += 2;
- _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga));
- buffer += 2;
- }
-
- SIMD_EPILOGUE(i, count, 3)
- *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
-}
-#endif
-
-template<QtPixelOrder PixelOrder>
-static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
-#ifdef __SSE2__
- qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
-#else
- for (int i = 0; i < count; ++i)
- buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
-#endif
- return buffer;
-}
-
-template<QtPixelOrder PixelOrder>
-static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- return convertA2RGB30PMToRGBA64PM<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 *)
-{
- uint *d = reinterpret_cast<uint *>(dest) + index;
- UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
-}
-
-template<QtPixelOrder PixelOrder>
-static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- uint *d = reinterpret_cast<uint *>(dest) + index;
- UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
-}
-
-template<QtPixelOrder PixelOrder>
-static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- uint *d = reinterpret_cast<uint *>(dest) + index;
- UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
-}
-
-template<bool RGBA>
-void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)
-{
- int i = 0;
-#ifdef __SSE2__
- if (((uintptr_t)dst & 0x7) && count > 0) {
- uint s = (*src++).toArgb32();
- if (RGBA)
- s = ARGB2RGBA(s);
- *dst++ = s;
- i++;
- }
- const __m128i vhalf = _mm_set1_epi32(0x80);
- const __m128i vzero = _mm_setzero_si128();
- for (; i < count-1; i += 2) {
- __m128i vs = _mm_loadu_si128((const __m128i*)src);
- src += 2;
- if (!RGBA) {
- vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
- vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
- }
- __m128i v1 = _mm_unpacklo_epi16(vs, vzero);
- __m128i v2 = _mm_unpackhi_epi16(vs, vzero);
- v1 = _mm_add_epi32(v1, vhalf);
- v2 = _mm_add_epi32(v2, vhalf);
- v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8));
- v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8));
- v1 = _mm_srli_epi32(v1, 8);
- v2 = _mm_srli_epi32(v2, 8);
- v1 = _mm_packs_epi32(v1, v2);
- v1 = _mm_packus_epi16(v1, vzero);
- _mm_storel_epi64((__m128i*)(dst), v1);
- dst += 2;
- }
-#endif
- for (; i < count; i++) {
- uint s = (*src++).toArgb32();
- if (RGBA)
- s = ARGB2RGBA(s);
- *dst++ = s;
- }
-}
-template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count);
-template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count);
-
-
-static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<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 *)
-{
- 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 *)
-{
- 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 *)
-{
- unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
- for (int i = 0; i < count; ++i)
- d[i] = qGray(src[i]) * 257;
-}
-
-static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
- for (int i = 0; i < count; ++i)
- d[i] = qGray(qUnpremultiply(src[i])) * 257;
-}
-
-static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
- for (int i = 0; i < count; ++i)
- buffer[i] = toArgb32(s[i]);
- return buffer;
-}
-
-static void QT_FASTCALL storeRGB64FromRGB32(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static void QT_FASTCALL convertRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const quint64 *src, int count)
{
- 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 fetchRGBA64ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
- for (int i = 0; i < count; ++i)
- buffer[i] = toArgb32(s[i].premultiplied());
- return buffer;
+ qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
}
-static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
- for (int i = 0; i < count; ++i)
- d[i] = QRgba64::fromArgb32(src[i]).unpremultiplied();
-}
-
-// 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] = {
- { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
- { false, false, QPixelLayout::BPP1MSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
- fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
- nullptr, nullptr }, // Format_Mono
- { false, false, QPixelLayout::BPP1LSB, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
- fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
- nullptr, nullptr }, // Format_MonoLSB
- { false, false, QPixelLayout::BPP8, nullptr,
- convertIndexedToARGB32PM, convertIndexedToRGBA64PM,
- fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
- nullptr, nullptr }, // Format_Indexed8
- // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
- // but everywhere this generic conversion would be wrong is currently overloaded.
- { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
- convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32
- { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM,
- convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32
- { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
- convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied
- pixelLayoutRGB<QImage::Format_RGB16>(),
- pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
- pixelLayoutRGB<QImage::Format_RGB666>(),
- pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(),
- pixelLayoutRGB<QImage::Format_RGB555>(),
- pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(),
- pixelLayoutRGB<QImage::Format_RGB888>(),
- pixelLayoutRGB<QImage::Format_RGB444>(),
- pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
- { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
- convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888
- { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM,
- convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888
- { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
- convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied
- { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
- convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
- convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
- fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
- fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
- storeRGB30FromARGB32PM<PixelOrderBGR>,
- storeRGB30FromRGB32<PixelOrderBGR>
- }, // Format_BGR30
- { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
- convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
- convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
- fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
- fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
- storeA2RGB30PMFromARGB32PM<PixelOrderBGR>,
- storeRGB30FromRGB32<PixelOrderBGR>
- }, // Format_A2BGR30_Premultiplied
- { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
- convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
- convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
- fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
- fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
- storeRGB30FromARGB32PM<PixelOrderRGB>,
- storeRGB30FromRGB32<PixelOrderRGB>
- }, // Format_RGB30
- { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
- convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
- convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
- fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
- fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
- storeA2RGB30PMFromARGB32PM<PixelOrderRGB>,
- storeRGB30FromRGB32<PixelOrderRGB>
- }, // Format_A2RGB30_Premultiplied
- { true, true, QPixelLayout::BPP8, nullptr,
- convertAlpha8ToRGB32, convertAlpha8ToRGB64,
- fetchAlpha8ToRGB32, fetchAlpha8ToRGB64,
- storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
- { false, false, QPixelLayout::BPP8, nullptr,
- convertGrayscale8ToRGB32, convertGrayscale8ToRGB64,
- fetchGrayscale8ToRGB32, fetchGrayscale8ToRGB64,
- storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
- { false, false, QPixelLayout::BPP64, nullptr,
- convertPassThrough, nullptr,
- fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBX64
- { true, false, QPixelLayout::BPP64, nullptr,
- convertARGB32ToARGB32PM, nullptr,
- fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
- storeRGBA64FromARGB32PM, storeRGB64FromRGB32 }, // Format_RGBA64
- { true, true, QPixelLayout::BPP64, nullptr,
- convertPassThrough, nullptr,
- fetchRGB64ToRGB32, fetchPassThrough64,
- storeRGB64FromRGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
- { false, false, QPixelLayout::BPP16, nullptr,
- convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
- fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
- storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
- pixelLayoutRGB<QImage::Format_BGR888>(),
+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,
};
-Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
-
-static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
-{
- for (int i = 0; i < length; ++i) {
- dest[i] = toArgb32(src[i]);
- }
-}
-
-template<QImage::Format format>
-static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither)
-{
- uint buffer[BufferSize];
- convertFromRgb64(buffer, src, count);
- qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
-}
+static_assert(std::size(convert64ToRGBA32F) == QImage::NImageFormats);
-static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static void convertRGBA32FToRGBA32FPM(QRgbaFloat32 *buffer, int count)
{
- uint *d = (uint*)dest + index;
for (int i = 0; i < count; ++i)
- d[i] = toArgb32(src[i].unpremultiplied());
+ buffer[i] = buffer[i].premultiplied();
}
-static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static void convertRGBA32FToRGBA32F(QRgbaFloat32 *, int)
{
- uint *d = (uint*)dest + index;
- for (int i = 0; i < count; ++i)
- d[i] = toRgba8888(src[i].unpremultiplied());
}
-template<QtPixelOrder PixelOrder>
-static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- uint *d = (uint*)dest + index;
-#ifdef __SSE2__
- qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
-#else
- for (int i = 0; i < count; ++i)
- d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]);
#endif
-}
-
-static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
- for (int i = 0; i < count; ++i) {
- d[i] = src[i].unpremultiplied();
- d[i].setAlpha(65535);
- }
-}
-
-static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
- for (int i = 0; i < count; ++i)
- d[i] = src[i].unpremultiplied();
-}
-
-static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
- if (d != src)
- memcpy(d, src, count * sizeof(QRgba64));
-}
-
-static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- quint16 *d = reinterpret_cast<quint16*>(dest) + index;
- for (int i = 0; i < count; ++i) {
- QRgba64 s = src[i].unpremultiplied();
- d[i] = qGray(s.red(), s.green(), s.blue());
- }
-}
-
-ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- storeGenericFromRGBA64PM<QImage::Format_RGB32>,
- storeARGB32FromRGBA64PM,
- storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>,
- storeGenericFromRGBA64PM<QImage::Format_RGB16>,
- storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>,
- storeGenericFromRGBA64PM<QImage::Format_RGB666>,
- storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>,
- storeGenericFromRGBA64PM<QImage::Format_RGB555>,
- storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>,
- storeGenericFromRGBA64PM<QImage::Format_RGB888>,
- storeGenericFromRGBA64PM<QImage::Format_RGB444>,
- storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>,
- storeGenericFromRGBA64PM<QImage::Format_RGBX8888>,
- storeRGBA8888FromRGBA64PM,
- storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>,
- storeRGB30FromRGBA64PM<PixelOrderBGR>,
- storeRGB30FromRGBA64PM<PixelOrderBGR>,
- storeRGB30FromRGBA64PM<PixelOrderRGB>,
- storeRGB30FromRGBA64PM<PixelOrderRGB>,
- storeGenericFromRGBA64PM<QImage::Format_Alpha8>,
- storeGenericFromRGBA64PM<QImage::Format_Grayscale8>,
- storeRGBX64FromRGBA64PM,
- storeRGBA64FromRGBA64PM,
- storeRGBA64PMFromRGBA64PM,
- storeGray16FromRGBA64PM,
- storeGenericFromRGBA64PM<QImage::Format_BGR888>,
-};
/*
Destination fetch. This is simple as we don't have to do bounds checks or
@@ -1711,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,
@@ -1743,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)
{
@@ -1762,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,
@@ -1794,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
/*
@@ -1803,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);
@@ -1903,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,
@@ -1929,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)
{
@@ -1953,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,
@@ -1979,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
/*
@@ -2053,10 +893,19 @@ 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)
{
- Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
+ static_assert(blendType == BlendTransformed || blendType == BlendTransformedTiled);
if (blendType == BlendTransformedTiled) {
if (v < 0 || v >= max) {
v %= max;
@@ -2088,7 +937,7 @@ template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
static void QT_FASTCALL fetchTransformed_fetcher(T *buffer, const QSpanData *data,
int y, int x, int length)
{
- Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
+ static_assert(blendType == BlendTransformed || blendType == BlendTransformedTiled);
const QTextureData &image = data->texture;
const qreal cx = x + qreal(0.5);
@@ -2097,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) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<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
@@ -2130,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;
@@ -2139,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;
@@ -2150,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;
@@ -2178,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;
@@ -2189,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;
@@ -2203,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;
@@ -2231,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];
@@ -2252,7 +1101,7 @@ template<TextureBlendType blendType, QPixelLayout::BPP bpp>
static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
int y, int x, int length)
{
- Q_STATIC_ASSERT(blendType == BlendTransformed || blendType == BlendTransformedTiled);
+ static_assert(blendType == BlendTransformed || blendType == BlendTransformedTiled);
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
fetchTransformed_fetcher<blendType, bpp, uint>(buffer, data, y, x, length);
layout->convertToARGB32PM(buffer, length, data->texture.colorTable);
@@ -2265,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)
@@ -2275,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
@@ -2416,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
@@ -2842,15 +1719,15 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint
fy += fdy;
++b;
}
- uint *boundedEnd = end; \
- if (fdx > 0) \
- boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx); \
- else if (fdx < 0) \
- boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx); \
- if (fdy > 0) \
- boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy); \
- else if (fdy < 0) \
- boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy); \
+ uint *boundedEnd = end;
+ if (fdx > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
+ else if (fdx < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
+ if (fdy > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy);
+ else if (fdy < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy);
// until boundedEnd we can now have a fast middle part without boundary checks
#if defined(__SSE2__)
@@ -2906,7 +1783,7 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint
int32x4_t v_fdy = vdupq_n_s32(fdy * 4);
const uchar *textureData = image.imageData;
- const int bytesPerLine = image.bytesPerLine;
+ const qsizetype bytesPerLine = image.bytesPerLine;
int32x4_t v_fx = vmovq_n_s32(fx);
int32x4_t v_fy = vmovq_n_s32(fy);
@@ -3053,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;
@@ -3152,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);
@@ -3250,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) ? qFetchPixel[layout.bpp] : fetchPixel<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;
@@ -3267,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 {
@@ -3284,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);
@@ -3303,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);
@@ -3330,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);
@@ -3359,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);
@@ -3385,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);
@@ -3402,13 +2279,64 @@ static void QT_FASTCALL fetchTransformedBilinear_fetcher(T *buf1, T *buf2, const
}
}
+template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
+static void QT_FASTCALL fetchTransformedBilinear_slow_fetcher(T *buf1, T *buf2, ushort *distxs, ushort *distys,
+ const int len, const QTextureData &image,
+ qreal &fx, qreal &fy, qreal &fw,
+ const qreal fdx, const qreal fdy, const qreal fdw)
+{
+ const QPixelLayout &layout = qPixelLayouts[image.format];
+ constexpr bool useFetch = (bpp < QPixelLayout::BPP32);
+ if (useFetch)
+ Q_ASSERT(sizeof(T) == sizeof(uint));
+ else
+ Q_ASSERT(layout.bpp == 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;
+ const qreal px = fx * iw - qreal(0.5);
+ const qreal py = fy * iw - qreal(0.5);
+
+ int x1 = qFloor(px);
+ int x2;
+ int y1 = qFloor(py);
+ int y2;
+
+ distxs[i] = ushort((px - x1) * (1<<16));
+ distys[i] = ushort((py - y1) * (1<<16));
+
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+
+ const uchar *s1 = image.scanLine(y1);
+ const uchar *s2 = image.scanLine(y2);
+ if constexpr (useFetch) {
+ buf1[i * 2 + 0] = fetch1(s1, x1);
+ buf1[i * 2 + 1] = fetch1(s1, x2);
+ buf2[i * 2 + 0] = fetch1(s2, x1);
+ buf2[i * 2 + 1] = fetch1(s2, x2);
+ } else {
+ buf1[i * 2 + 0] = reinterpret_cast<const T *>(s1)[x1];
+ buf1[i * 2 + 1] = reinterpret_cast<const T *>(s1)[x2];
+ buf2[i * 2 + 0] = reinterpret_cast<const T *>(s2)[x1];
+ buf2[i * 2 + 1] = reinterpret_cast<const T *>(s2)[x2];
+ }
+
+ fx += fdx;
+ fy += fdy;
+ fw += fdw;
+ }
+}
+
// blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
template<TextureBlendType blendType, QPixelLayout::BPP bpp>
static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
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);
@@ -3512,10 +2440,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
}
}
} else {
- // When templated 'fetch' should be inlined at compile time:
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : fetchPixel<bpp>;
-
- const QTextureData &image = data->texture;
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType,bpp,uint>;
const qreal fdx = data->m11;
const qreal fdy = data->m12;
@@ -3529,48 +2454,19 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
uint buf2[BufferSize];
uint *b = buffer;
- int distxs[BufferSize / 2];
- int distys[BufferSize / 2];
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
while (length) {
- int len = qMin(length, BufferSize / 2);
- for (int i = 0; i < len; ++i) {
- const qreal iw = fw == 0 ? 1 : 1 / fw;
- const qreal px = fx * iw - qreal(0.5);
- const qreal py = fy * iw - qreal(0.5);
-
- int x1 = int(px) - (px < 0);
- int x2;
- int y1 = int(py) - (py < 0);
- int y2;
-
- distxs[i] = int((px - x1) * 256);
- distys[i] = int((py - y1) * 256);
-
- fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
-
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
- buf1[i * 2 + 0] = fetch1(s1, x1);
- buf1[i * 2 + 1] = fetch1(s1, x2);
- buf2[i * 2 + 0] = fetch1(s2, x1);
- buf2[i * 2 + 1] = fetch1(s2, x2);
-
- fx += fdx;
- fy += fdy;
- fw += fdw;
- //force increment to avoid /0
- if (!fw)
- fw += fdw;
- }
+ const int len = qMin(length, BufferSize / 2);
+ fetcher(buf1, buf2, distxs, distys, len, data->texture, fx, fy, fw, fdx, fdy, fdw);
layout->convertToARGB32PM(buf1, len * 2, clut);
layout->convertToARGB32PM(buf2, len * 2, clut);
for (int i = 0; i < len; ++i) {
- int distx = distxs[i];
- int disty = distys[i];
+ const int distx = distxs[i] >> 8;
+ const int disty = distys[i] >> 8;
b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
}
@@ -3587,9 +2483,9 @@ template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buffer, const QSpanData *data,
int y, int x, int length)
{
- const QTextureData &texture = data->texture;
- const QPixelLayout *layout = &qPixelLayouts[texture.format];
- const QVector<QRgb> *clut = data->texture.colorTable;
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ 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);
@@ -3598,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)) {
@@ -3619,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) {
@@ -3657,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;
@@ -3678,7 +2573,10 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
}
}
} else { // !(data->fast_matrix)
- const QTextureData &image = data->texture;
+ 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;
@@ -3688,51 +2586,19 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint32(QRgba64 *buf
qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
- FetchPixelFunc fetch = qFetchPixel[layout->bpp];
-
- int distxs[BufferSize / 2];
- int distys[BufferSize / 2];
-
- while (b < end) {
- int len = qMin(length, BufferSize / 2);
- for (int i = 0; i < len; ++i) {
- const qreal iw = fw == 0 ? 1 : 1 / fw;
- const qreal px = fx * iw - qreal(0.5);
- const qreal py = fy * iw - qreal(0.5);
-
- int x1 = qFloor(px);
- int x2;
- int y1 = qFloor(py);
- int y2;
-
- distxs[i] = int((px - x1) * (1<<16));
- distys[i] = int((py - y1) * (1<<16));
-
- fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ ushort distxs[BufferSize / 2];
+ ushort distys[BufferSize / 2];
- const uchar *s1 = texture.scanLine(y1);
- const uchar *s2 = texture.scanLine(y2);
-
- sbuf1[i * 2 + 0] = fetch(s1, x1);
- sbuf1[i * 2 + 1] = fetch(s1, x2);
- sbuf2[i * 2 + 0] = fetch(s2, x1);
- sbuf2[i * 2 + 1] = fetch(s2, x2);
-
- fx += fdx;
- fy += fdy;
- fw += fdw;
- //force increment to avoid /0
- if (!fw)
- fw += fdw;
- }
+ while (length) {
+ 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) {
- int distx = distxs[i];
- int disty = distys[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);
}
@@ -3747,9 +2613,7 @@ template<TextureBlendType blendType>
static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buffer, const QSpanData *data,
int y, int x, int length)
{
- const QTextureData &texture = data->texture;
- Q_ASSERT(qPixelLayouts[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);
@@ -3832,7 +2696,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf
}
}
} else { // !(data->fast_matrix)
- const QTextureData &image = data->texture;
+ const auto fetcher = fetchTransformedBilinear_slow_fetcher<blendType, QPixelLayout::BPP64, QRgba64>;
const qreal fdx = data->m11;
const qreal fdy = data->m12;
@@ -3842,49 +2706,104 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64_uint64(QRgba64 *buf
qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
- int distxs[BufferSize / 2];
- int distys[BufferSize / 2];
+ 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);
- while (b < end) {
- int len = qMin(length, BufferSize / 2);
for (int i = 0; i < len; ++i) {
- const qreal iw = fw == 0 ? 1 : 1 / fw;
- const qreal px = fx * iw - qreal(0.5);
- const qreal py = fy * iw - qreal(0.5);
+ const int distx = distxs[i];
+ const int disty = distys[i];
+ b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty);
+ }
- int x1 = int(px) - (px < 0);
- int x2;
- int y1 = int(py) - (py < 0);
- int y2;
+ length -= len;
+ b += len;
+ }
+ }
+ return buffer;
+}
- distxs[i] = int((px - x1) * (1<<16));
- distys[i] = int((py - y1) * (1<<16));
+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;
- fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ 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);
- const uchar *s1 = texture.scanLine(y1);
- const uchar *s2 = texture.scanLine(y2);
+ 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);
- buf1[i * 2 + 0] = reinterpret_cast<const QRgba64 *>(s1)[x1];
- buf1[i * 2 + 1] = reinterpret_cast<const QRgba64 *>(s1)[x2];
- buf2[i * 2 + 0] = reinterpret_cast<const QRgba64 *>(s2)[x1];
- buf2[i * 2 + 1] = reinterpret_cast<const QRgba64 *>(s2)[x2];
+ 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;
- fw += fdw;
- //force increment to avoid /0
- if (!fw)
- fw += fdw;
}
- convert(buf1, len * 2);
- convert(buf2, len * 2);
+ 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) {
- int distx = distxs[i];
- int disty = distys[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);
}
@@ -3899,14 +2818,280 @@ 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
@@ -3937,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
@@ -3948,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
@@ -3957,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
@@ -3966,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
@@ -3975,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)
@@ -3989,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
@@ -3998,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
@@ -4007,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)
@@ -4015,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)
{
@@ -4033,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;
@@ -4053,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)
@@ -4073,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)
@@ -4086,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,
@@ -4114,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);
@@ -4169,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)
{
@@ -4179,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;
}
@@ -4212,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;
@@ -4238,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,
@@ -4303,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
@@ -4340,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;
@@ -4360,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;
@@ -4368,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;
@@ -4375,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:
@@ -4388,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;
@@ -4399,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) {
@@ -4421,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
}
}
@@ -4432,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;
@@ -4443,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);
@@ -4476,45 +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();
- bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source
- || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && qAlpha(color) == 255);
- 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;
- }
+ 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;
+
+ 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
@@ -4522,6 +3889,10 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x;
if (spans->coverage == 255) {
qt_memfill(target, color, spans->len);
+#ifdef __SSE2__
+ } else if (spans->len > 16) {
+ op.funcSolid(target, spans->len, color, spans->coverage);
+#endif
} else {
uint c = BYTE_MUL(color, spans->coverage);
int ialpha = 255 - spans->coverage;
@@ -4532,219 +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;
- bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source
- || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && color.isOpaque());
- QPixelLayout::BPP bpp = qPixelLayouts[data->rasterBuffer->format].bpp;
+ 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);
}
@@ -4761,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}
{
}
@@ -4774,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);
}
@@ -4793,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
@@ -4923,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,
@@ -5006,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;
@@ -5024,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;
@@ -5083,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;
@@ -5137,7 +4609,9 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
yoff += image_height;
bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
- if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && isBpp32) {
+ 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;
@@ -5171,47 +4645,116 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
if (sx >= image_width)
sx = 0;
}
- uint *dest = (uint*)data->rasterBuffer->scanLine(y) + x - image_width;
- for (int i = image_width; i < length; ++i) {
- dest[i] = dest[i - image_width];
+ if (isBpp32) {
+ uint *dest = reinterpret_cast<uint *>(data->rasterBuffer->scanLine(y)) + x - image_width;
+ for (int i = image_width; i < length; ++i)
+ dest[i] = dest[i - image_width];
+ } else {
+ quint64 *dest = reinterpret_cast<quint64 *>(data->rasterBuffer->scanLine(y)) + x - image_width;
+ for (int i = image_width; i < length; ++i)
+ dest[i] = dest[i - image_width];
}
++spans;
}
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
@@ -5220,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;
@@ -5231,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;
@@ -5283,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 */
@@ -5397,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:
@@ -5422,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;
@@ -5435,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:
@@ -5459,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;
@@ -5473,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;
@@ -5495,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 =
@@ -5510,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:
@@ -5531,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();
@@ -5555,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) {
@@ -5585,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) {
@@ -5769,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);
@@ -5843,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);
@@ -5893,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;
@@ -5911,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);
@@ -5947,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);
@@ -5968,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);
@@ -6048,7 +5657,11 @@ static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba
// Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
blend_pixel(*dst, src, qRgbAvg(coverage));
} else if (!colorProfile) {
- *dst = rgbBlend(*dst, src, coverage);
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then a naive blend with glyph shape
+ *dst = rgbBlend(*dst, s, coverage);
} else if (srcLinear.isOpaque()) {
rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
@@ -6065,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);
@@ -6144,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);
@@ -6217,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);
@@ -6261,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);
@@ -6283,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);
@@ -6391,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 },
@@ -6439,7 +6063,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
},
// Format_RGB16
{
- blend_color_rgb16,
+ blend_color_generic,
qt_bitmapblit_quint16,
qt_alphamapblit_quint16,
qt_alphargbblit_generic,
@@ -6621,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)
@@ -6690,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();
@@ -6712,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
@@ -6762,10 +6438,12 @@ static void qInitDrawhelperFunctions()
extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha);
extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha);
qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2;
qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2;
qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2;
+ qt_functionForModeSolid_C[QPainter::CompositionMode_Source] = comp_func_solid_Source_sse2;
qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2;
#ifdef QT_COMPILER_SUPPORTS_SSSE3
@@ -6790,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;
@@ -6835,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
@@ -6875,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*/);
@@ -6887,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
@@ -6937,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 fb50cb6a50..34de69ecf4 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -1,46 +1,11 @@
-/****************************************************************************
-**
-** 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"
#include "qdrawingprimitive_sse2_p.h"
+#include "qpixellayout_p.h"
#include "qrgba64_p.h"
#if defined(QT_COMPILER_SUPPORTS_AVX2)
@@ -142,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)
{
@@ -359,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
@@ -456,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) {
@@ -522,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) {
@@ -586,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 */ \
@@ -1088,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;
@@ -1201,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 8196a87b24..1fceb83710 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -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
#include <private/qdrawhelper_neon_p.h>
#include <private/qblendfunctions_p.h>
#include <private/qmath_p.h>
+#include <private/qpixellayout_p.h>
#ifdef __ARM_NEON__
@@ -220,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;
@@ -263,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)
@@ -272,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;
@@ -1311,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 dd42b96d79..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
@@ -61,16 +25,17 @@
#define QT_FT_BEGIN_HEADER
#define QT_FT_END_HEADER
#endif
+#include "private/qpixellayout_p.h"
#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
@@ -88,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;
@@ -107,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,
@@ -149,8 +110,6 @@ typedef void (*SrcOverTransformFunc)(uchar *destPixels, int dbpl,
const QTransform &targetRectTransform,
int const_alpha);
-typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
-
struct DrawHelper {
ProcessSpans blendColor;
BitmapBlitFunc bitmapBlit;
@@ -181,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
@@ -195,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
{
@@ -213,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
{
@@ -240,6 +203,12 @@ struct Operator
CompositionFunctionSolid64 funcSolid64;
CompositionFunction64 func64;
+ DestFetchProcFP destFetchFP;
+ DestStoreProcFP destStoreFP;
+ SourceFetchProcFP srcFetchFP;
+ CompositionFunctionSolidFP funcSolidFP;
+ CompositionFunctionFP funcFP;
+
union {
LinearGradientValues linear;
RadialGradientValues radial;
@@ -296,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];
@@ -318,11 +287,12 @@ struct QTextureData
int y2;
qsizetype bytesPerLine;
QImage::Format format;
- const QVector<QRgb> *colorTable;
+ const QList<QRgb> *colorTable;
bool hasAlpha;
enum Type {
Plain,
- Tiled
+ Tiled,
+ Pattern
};
Type type;
int const_alpha;
@@ -350,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();
@@ -435,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;
@@ -473,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;
@@ -485,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);
@@ -601,12 +567,12 @@ public:
FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD)
break;
default:
- Q_ASSERT(false);
+ Q_UNREACHABLE();
}
}
};
-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;
@@ -620,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;
@@ -628,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;
@@ -637,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;
@@ -648,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;
@@ -661,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;
@@ -669,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);
@@ -680,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());
@@ -721,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));
@@ -845,57 +811,75 @@ static inline QRgba64 interpolate_4_pixels_rgb64(const QRgba64 t[], const QRgba6
}
#endif // __SSE2__
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) {
- quint32 rgb = x >> 8;
- quint32 a = x << 24;
- return a | rgb;
+#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 Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) {
- quint32 rgb = x << 8;
- quint32 a = x >> 24;
- return a | rgb;
+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 };
}
-#else
-static Q_ALWAYS_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);
+#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 Q_ALWAYS_INLINE quint32 ARGB2RGBA(quint32 x) {
- return RGBA2ARGB(x);
-}
+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 Q_ALWAYS_INLINE uint BYTE_MUL_RGB16(uint x, uint a) {
+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 Q_ALWAYS_INLINE uint qAlphaRgb30(uint c)
-{
- uint a = c >> 30;
- a |= a << 2;
- a |= a << 4;
- return a;
-}
+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)
{
@@ -978,214 +962,6 @@ inline QRgb qConvertRgb16To32(uint c)
| ((((c) << 8) & 0xf80000) | (((c) << 3) & 0x70000));
}
-enum QtPixelOrder {
- PixelOrderRGB,
- PixelOrderBGR
-};
-
-template<enum QtPixelOrder> inline uint qConvertArgb32ToA2rgb30(QRgb);
-
-template<enum QtPixelOrder> inline uint qConvertRgb32ToRgb30(QRgb);
-
-template<enum QtPixelOrder> inline QRgb qConvertA2rgb30ToArgb32(uint c);
-
-// A combined unpremultiply and premultiply with new simplified alpha.
-// Needed when alpha loses precision relative to other colors during conversion (ARGB32 -> A2RGB30).
-template<unsigned int Shift>
-inline QRgb qRepremultiply(QRgb p)
-{
- const uint alpha = qAlpha(p);
- if (alpha == 255 || alpha == 0)
- return p;
- p = qUnpremultiply(p);
- Q_CONSTEXPR uint mult = 255 / (255 >> Shift);
- const uint newAlpha = mult * (alpha >> Shift);
- p = (p & ~0xff000000) | (newAlpha<<24);
- return qPremultiply(p);
-}
-
-template<unsigned int Shift>
-inline QRgba64 qRepremultiply(QRgba64 p)
-{
- const uint alpha = p.alpha();
- if (alpha == 65535 || alpha == 0)
- return p;
- p = p.unpremultiplied();
- Q_CONSTEXPR uint mult = 65535 / (65535 >> Shift);
- p.setAlpha(mult * (alpha >> Shift));
- return p.premultiplied();
-}
-
-template<>
-inline uint qConvertArgb32ToA2rgb30<PixelOrderBGR>(QRgb c)
-{
- c = qRepremultiply<6>(c);
- return (c & 0xc0000000)
- | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000))
- | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
- | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003));
-}
-
-template<>
-inline uint qConvertArgb32ToA2rgb30<PixelOrderRGB>(QRgb c)
-{
- c = qRepremultiply<6>(c);
- return (c & 0xc0000000)
- | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000))
- | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
- | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003));
-}
-
-template<>
-inline uint qConvertRgb32ToRgb30<PixelOrderBGR>(QRgb c)
-{
- return 0xc0000000
- | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000))
- | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
- | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003));
-}
-
-template<>
-inline uint qConvertRgb32ToRgb30<PixelOrderRGB>(QRgb c)
-{
- return 0xc0000000
- | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000))
- | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
- | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003));
-}
-
-template<>
-inline QRgb qConvertA2rgb30ToArgb32<PixelOrderBGR>(uint c)
-{
- uint a = c >> 30;
- a |= a << 2;
- a |= a << 4;
- return (a << 24)
- | ((c << 14) & 0x00ff0000)
- | ((c >> 4) & 0x0000ff00)
- | ((c >> 22) & 0x000000ff);
-}
-
-template<>
-inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c)
-{
- uint a = c >> 30;
- a |= a << 2;
- a |= a << 4;
- return (a << 24)
- | ((c >> 6) & 0x00ff0000)
- | ((c >> 4) & 0x0000ff00)
- | ((c >> 2) & 0x000000ff);
-}
-
-template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb);
-
-template<>
-inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb)
-{
- quint16 alpha = rgb >> 30;
- quint16 blue = (rgb >> 20) & 0x3ff;
- quint16 green = (rgb >> 10) & 0x3ff;
- quint16 red = rgb & 0x3ff;
- // Expand the range.
- alpha |= (alpha << 2);
- alpha |= (alpha << 4);
- alpha |= (alpha << 8);
- red = (red << 6) | (red >> 4);
- green = (green << 6) | (green >> 4);
- blue = (blue << 6) | (blue >> 4);
- return qRgba64(red, green, blue, alpha);
-}
-
-template<>
-inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb)
-{
- quint16 alpha = rgb >> 30;
- quint16 red = (rgb >> 20) & 0x3ff;
- quint16 green = (rgb >> 10) & 0x3ff;
- quint16 blue = rgb & 0x3ff;
- // Expand the range.
- alpha |= (alpha << 2);
- alpha |= (alpha << 4);
- alpha |= (alpha << 8);
- red = (red << 6) | (red >> 4);
- green = (green << 6) | (green >> 4);
- blue = (blue << 6) | (blue >> 4);
- return qRgba64(red, green, blue, alpha);
-}
-
-template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64);
-
-template<>
-inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c)
-{
- c = qRepremultiply<14>(c);
- const uint a = c.alpha() >> 14;
- const uint r = c.red() >> 6;
- const uint g = c.green() >> 6;
- const uint b = c.blue() >> 6;
- return (a << 30) | (b << 20) | (g << 10) | r;
-}
-
-template<>
-inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c)
-{
- c = qRepremultiply<14>(c);
- const uint a = c.alpha() >> 14;
- const uint r = c.red() >> 6;
- const uint g = c.green() >> 6;
- const uint b = c.blue() >> 6;
- return (a << 30) | (r << 20) | (g << 10) | b;
-}
-
-inline uint qRgbSwapRgb30(uint c)
-{
- const uint ag = c & 0xc00ffc00;
- const uint rb = c & 0x3ff003ff;
- return ag | (rb << 20) | (rb >> 20);
-}
-
-inline int qRed565(quint16 rgb) {
- const int r = (rgb & 0xf800);
- return (r >> 8) | (r >> 13);
-}
-
-inline int qGreen565(quint16 rgb) {
- const int g = (rgb & 0x07e0);
- return (g >> 3) | (g >> 9);
-}
-
-inline int qBlue565(quint16 rgb) {
- const int b = (rgb & 0x001f);
- return (b << 3) | (b >> 2);
-}
-
-// We manually unalias the variables to make sure the compiler
-// fully optimizes both aliased and unaliased cases.
-#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \
- if (src == buffer) { \
- for (int i = 0; i < count; ++i) \
- buffer[i] = conversion(buffer[i]); \
- } else { \
- for (int i = 0; i < count; ++i) \
- buffer[i] = conversion(src[i]); \
- }
-
-
-static Q_ALWAYS_INLINE const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count)
-{
- UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply);
- return buffer;
-}
-
-static Q_ALWAYS_INLINE const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count)
-{
- UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));});
- return buffer;
-}
-
-template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count);
-
const uint qt_bayer_matrix[16][16] = {
{ 0x1, 0xc0, 0x30, 0xf0, 0xc, 0xcc, 0x3c, 0xfc,
0x3, 0xc3, 0x33, 0xf3, 0xf, 0xcf, 0x3f, 0xff},
@@ -1250,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
@@ -1265,61 +1041,6 @@ struct IntermediateBuffer
quint32 buffer_ag[BufferSize+2];
};
-struct QDitherInfo {
- int x;
- int y;
-};
-
-typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither);
-typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither);
-
-typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither);
-typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither);
-
-typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QVector<QRgb> *clut);
-typedef void (QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QVector<QRgb> *clut);
-typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count,
- const QVector<QRgb> *clut, QDitherInfo *dither);
-typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count);
-
-
-struct QPixelLayout
-{
- // Bits per pixel
- enum BPP {
- BPPNone,
- BPP1MSB,
- BPP1LSB,
- BPP8,
- BPP16,
- BPP24,
- BPP32,
- BPP64,
- BPPCount
- };
-
- bool hasAlphaChannel;
- bool premultiplied;
- BPP bpp;
- RbSwapFunc rbSwap;
- ConvertFunc convertToARGB32PM;
- ConvertTo64Func convertToRGBA64PM;
- FetchAndConvertPixelsFunc fetchToARGB32PM;
- FetchAndConvertPixelsFunc64 fetchToRGBA64PM;
- ConvertAndStorePixelsFunc storeFromARGB32PM;
- ConvertAndStorePixelsFunc storeFromRGB32;
-};
-
-extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats];
-
-extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
-
-extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
-
QT_END_NAMESPACE
#endif // QDRAWHELPER_P_H
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index c82f41ec88..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,36 @@ 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)
+{
+ if (const_alpha == 255) {
+ qt_memfill32(destPixels, color, length);
+ } else {
+ const quint32 ialpha = 255 - const_alpha;
+ color = BYTE_MUL(color, const_alpha);
+ int x = 0;
+
+ quint32 *dst = (quint32 *) destPixels;
+ const __m128i colorVector = _mm_set1_epi32(color);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i iAlphaVector = _mm_set1_epi16(ialpha);
+
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha);
+
+ for (; x < length-3; x += 4) {
+ __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
+ BYTE_MUL_SSE2(dstVector, dstVector, iAlphaVector, colorMask, half);
+ dstVector = _mm_add_epi8(colorVector, dstVector);
+ _mm_store_si128((__m128i *)&dst[x], dstVector);
+ }
+ SIMD_EPILOGUE(x, length, 3)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], ialpha);
+ }
+}
void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha)
{
@@ -368,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)
@@ -387,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);
@@ -430,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)
@@ -504,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();
-
- int ix = 0x00010000 / sx;
- int iy = 0x00010000 / sy;
+ qreal sx = sourceRect.width() / (qreal)targetRect.width();
+ qreal sy = sourceRect.height() / (qreal)targetRect.height();
- int cx1 = clip.x();
- int cx2 = clip.x() + clip.width();
- int cy1 = clip.top();
- int cy2 = clip.y() + clip.height();
+ const int ix = 0x00010000 * sx;
+ const int iy = 0x00010000 * sy;
- 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);
@@ -589,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;
@@ -602,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 68d887ae6d..a7b4e6ba76 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -1,51 +1,16 @@
-/****************************************************************************
-**
-** 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>
#include <private/qpaintengine_raster_p.h>
+#include <private/qpixellayout_p.h>
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
QT_BEGIN_NAMESPACE
-#ifndef __AVX2__
+#ifndef __haswell__
template<bool RGBA>
static void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count)
{
@@ -141,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)
{
@@ -326,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);
@@ -410,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)
{
@@ -432,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 5749d8c9fb..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
@@ -77,9 +41,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
int w, int h,
int const_alpha);
-extern CompositionFunction qt_functionForMode_SSE2[];
-extern CompositionFunctionSolid qt_functionForModeSolid_SSE2[];
-
void qt_memfill64_avx2(quint64 *dest, quint64 value, qsizetype count);
void qt_memfill32_avx2(quint32 *dest, quint32 value, qsizetype count);
#endif // __SSE2__
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 18f212f8e9..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
{
@@ -87,16 +59,26 @@ constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d)
return (a << 24) | (b << 16) | (c << 8) | 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'),
@@ -105,10 +87,21 @@ enum class Tag : quint32 {
rTRC = IccTag('r', 'T', 'R', 'C'),
gTRC = IccTag('g', 'T', 'R', 'C'),
bTRC = IccTag('b', 'T', 'R', 'C'),
+ 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'),
@@ -119,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:
@@ -130,7 +125,9 @@ enum class Tag : quint32 {
aabg = IccTag('a', 'a', 'b', 'g'),
};
-inline uint qHash(const Tag &key, uint seed = 0)
+} // namespace QIcc
+
+inline size_t qHash(const QIcc::Tag &key, size_t seed = 0)
{
return qHash(quint32(key), seed);
}
@@ -157,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
};
@@ -185,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;
@@ -195,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)
@@ -219,25 +280,30 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
}
// Don't overflow 32bit integers:
- if (header.tagCount >= INT32_MAX / sizeof(TagTableEntry))
+ if (header.tagCount >= (INT32_MAX - sizeof(ICCProfileHeader)) / sizeof(TagTableEntry)) {
+ qCWarning(lcIcc, "Failed tag count sanity");
return false;
+ }
if (header.profileSize - sizeof(ICCProfileHeader) < header.tagCount * sizeof(TagTableEntry)) {
qCWarning(lcIcc, "Failed basic size sanity");
return false;
}
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 != 0x52474220 /* 'RGB '*/) {
- qCWarning(lcIcc, "Unsupported ICC input color space %x", quint32(header.inputColorSpace));
+ if (header.inputColorSpace != uint(ColorSpaceType::Rgb)
+ && 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;
}
@@ -255,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;
@@ -295,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;
}
@@ -304,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;
@@ -320,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);
@@ -337,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);
@@ -368,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;
@@ -393,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();
@@ -433,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 {
@@ -484,189 +595,521 @@ 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<quint16> utf16hostendian(stringLen);
- qFromBigEndian<ushort>(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)
{
- if (data.size() < qsizetype(sizeof(ICCProfileHeader))) {
- qCWarning(lcIcc) << "fromIccProfile: failed size sanity 1";
+ if (tagEntry.size < sizeof(mABTagData)) {
+ qCWarning(lcIcc) << "Undersized mAB/mBA tag";
return false;
}
- const ICCProfileHeader *header = (const ICCProfileHeader *)data.constData();
- if (!isValidIccProfile(*header)) {
- qCWarning(lcIcc) << "fromIccProfile: failed general sanity check";
+ if (qsizetype(tagEntry.size) > data.size()) {
+ qCWarning(lcIcc) << "Truncated mAB/mBA tag";
return false;
}
- 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);
- 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;
+ }
+ 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;
}
-// 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 });
- }
- // Check the profile is three-component matrix based (what we currently support):
- 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";
+ 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;
}
- QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::getWritable(*colorSpace);
+ 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 {
+ 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));
+ }
+
+ return true;
+}
+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 (tagEntry.size - 12 < len)
+ return false;
+ 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;
+
+ 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;
@@ -676,6 +1119,10 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
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;
+ }
colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) {
@@ -692,15 +1139,61 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb;
}
- // Reset the matrix to our canonical values:
- if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom)
- colorspaceDPtr->setToXyzMatrix();
+ 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;
+}
- // Parse TRC tags
+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 (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) {
+ if (isColorSpaceTypeGray) {
+ rTrc = tagIndex[Tag::kTRC];
+ gTrc = tagIndex[Tag::kTRC];
+ bTrc = tagIndex[Tag::kTRC];
+ } else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) {
// Apple extension for parametric version of TRCs in ICCv2:
rTrc = tagIndex[Tag::aarg];
gTrc = tagIndex[Tag::aagg];
@@ -714,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;
@@ -745,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 {
@@ -754,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;
@@ -768,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 2e2f65b483..a636635fd5 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -1,47 +1,19 @@
-/****************************************************************************
-**
-** 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 <private/qthreadpool_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -239,6 +211,8 @@ static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img,
isi = new QImageScaleInfo;
if (!isi)
return nullptr;
+ isi->sh = sh;
+ isi->sw = sw;
isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1);
@@ -294,6 +268,33 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
int dw, int dh, int dow, int sow);
#endif
+template<typename T>
+static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
+{
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
+ }
+#else
+ Q_UNUSED(isi);
+#endif
+ scaleSection(0, dh);
+}
+
static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest,
int dw, int dh, int dow, int sow)
{
@@ -303,33 +304,36 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest,
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- /* calculate the source line we'll scan from */
- const unsigned int *sptr = ypoints[y];
- unsigned int *dptr = dest + (y * dow);
- const int yap = yapoints[y];
- if (yap > 0) {
- for (int x = 0; x < dw; x++) {
- const unsigned int *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap);
- else
- *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap);
- dptr++;
- }
- } else {
- for (int x = 0; x < dw; x++) {
- const unsigned int *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
- else
- *dptr = pix[0];
- dptr++;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ /* calculate the source line we'll scan from */
+ const unsigned int *sptr = ypoints[y];
+ unsigned int *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap);
+ else
+ *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
}
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
/* scale by area sampling - with alpha */
@@ -411,33 +415,36 @@ static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b, a;
- qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a);
-
- int xap = xapoints[x];
- if (xap > 0) {
- int rr, gg, bb, aa;
- qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- a = a * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
- a = (a + (aa * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b, a;
+ qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ int rr, gg, bb, aa;
+ qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ a = a * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ a = (a + (aa * xap)) >> 8;
+ }
+ *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
}
- *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
@@ -449,34 +456,37 @@ static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b, a;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a);
-
- int yap = yapoints[y];
- if (yap > 0) {
- int rr, gg, bb, aa;
- qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- a = a * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
- a = (a + (aa * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b, a;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ int rr, gg, bb, aa;
+ qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ a = a * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ a = (a + (aa * yap)) >> 8;
+ }
+ *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
+ dptr++;
}
- *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest,
@@ -487,45 +497,48 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int rx, gx, bx, ax;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
- int r = ((rx>>4) * yap);
- int g = ((gx>>4) * yap);
- int b = ((bx>>4) * yap);
- int a = ((ax>>4) * yap);
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int rx, gx, bx, ax;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ int r = ((rx>>4) * yap);
+ int g = ((gx>>4) * yap);
+ int b = ((bx>>4) * yap);
+ int a = ((ax>>4) * yap);
+
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += ((rx>>4) * Cy);
+ g += ((gx>>4) * Cy);
+ b += ((bx>>4) * Cy);
+ a += ((ax>>4) * Cy);
+ }
sptr += sow;
qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += ((rx>>4) * Cy);
- g += ((gx>>4) * Cy);
- b += ((bx>>4) * Cy);
- a += ((ax>>4) * Cy);
- }
- sptr += sow;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += ((rx>>4) * j);
- g += ((gx>>4) * j);
- b += ((bx>>4) * j);
- a += ((ax>>4) * j);
+ r += ((rx>>4) * j);
+ g += ((gx>>4) * j);
+ b += ((bx>>4) * j);
+ a += ((ax>>4) * j);
- *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
- dptr++;
+ *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
+ dptr++;
+ }
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
#if QT_CONFIG(raster_64bit)
@@ -546,32 +559,35 @@ static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- const QRgba64 *sptr = ypoints[y];
- QRgba64 *dptr = dest + (y * dow);
- const int yap = yapoints[y];
- if (yap > 0) {
- for (int x = 0; x < dw; x++) {
- const QRgba64 *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256);
- else
- *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap);
- dptr++;
- }
- } else {
- for (int x = 0; x < dw; x++) {
- const QRgba64 *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
- else
- *dptr = pix[0];
- dptr++;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba64 *sptr = ypoints[y];
+ QRgba64 *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256);
+ else
+ *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
}
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest,
@@ -616,33 +632,36 @@ static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 r, g, b, a;
- qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a);
-
- int xap = xapoints[x];
- if (xap > 0) {
- qint64 rr, gg, bb, aa;
- qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- a = a * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
- a = (a + (aa * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 r, g, b, a;
+ qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ qint64 rr, gg, bb, aa;
+ qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ a = a * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ a = (a + (aa * xap)) >> 8;
+ }
+ *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
}
- *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
@@ -653,34 +672,37 @@ static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 r, g, b, a;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a);
-
- int yap = yapoints[y];
- if (yap > 0) {
- qint64 rr, gg, bb, aa;
- qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- a = a * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
- a = (a + (aa * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 r, g, b, a;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ qint64 rr, gg, bb, aa;
+ qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ a = a * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ a = (a + (aa * yap)) >> 8;
+ }
+ *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
+ dptr++;
}
- *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
@@ -691,43 +713,261 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 rx, gx, bx, ax;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
-
- qint64 r = rx * yap;
- qint64 g = gx * yap;
- qint64 b = bx * yap;
- qint64 a = ax * yap;
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 rx, gx, bx, ax;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+
+ qint64 r = rx * yap;
+ qint64 g = gx * yap;
+ qint64 b = bx * yap;
+ qint64 a = ax * yap;
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += rx * Cy;
+ g += gx * Cy;
+ b += bx * Cy;
+ a += ax * Cy;
+ }
sptr += sow;
qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += rx * Cy;
- g += gx * Cy;
- b += bx * Cy;
- a += ax * Cy;
+ r += rx * j;
+ g += gx * j;
+ b += bx * j;
+ a += ax * j;
+
+ *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
+ dptr++;
}
- sptr += sow;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += rx * j;
- g += gx * j;
- b += bx * j;
- a += ax * j;
-
- *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
- dptr++;
}
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
+}
+#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
@@ -817,31 +1057,34 @@ static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b;
- qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b);
-
- int xap = xapoints[x];
- if (xap > 0) {
- int rr, bb, gg;
- qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b;
+ qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ int rr, bb, gg;
+ qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ }
+ *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
@@ -853,31 +1096,34 @@ static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b);
-
- int yap = yapoints[y];
- if (yap > 0) {
- int rr, bb, gg;
- qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ int rr, bb, gg;
+ qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ }
+ *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest,
@@ -888,43 +1134,46 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int rx, gx, bx;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int rx, gx, bx;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
- int r = (rx >> 4) * yap;
- int g = (gx >> 4) * yap;
- int b = (bx >> 4) * yap;
+ int r = (rx >> 4) * yap;
+ int g = (gx >> 4) * yap;
+ int b = (bx >> 4) * yap;
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
+
+ r += (rx >> 4) * Cy;
+ g += (gx >> 4) * Cy;
+ b += (bx >> 4) * Cy;
+ }
sptr += sow;
qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
- r += (rx >> 4) * Cy;
- g += (gx >> 4) * Cy;
- b += (bx >> 4) * Cy;
- }
- sptr += sow;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
-
- r += (rx >> 4) * j;
- g += (gx >> 4) * j;
- b += (bx >> 4) * j;
+ r += (rx >> 4) * j;
+ g += (gx >> 4) * j;
+ b += (bx >> 4) * j;
- *dptr = qRgb(r >> 24, g >> 24, b >> 24);
- dptr++;
+ *dptr = qRgb(r >> 24, g >> 24, b >> 24);
+ dptr++;
+ }
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
@@ -947,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 4ae113b002..074b819862 100644
--- a/src/gui/painting/qimagescale_neon.cpp
+++ b/src/gui/painting/qimagescale_neon.cpp
@@ -1,52 +1,47 @@
-/****************************************************************************
-**
-** 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 <private/qthreadpool_p.h>
+#endif
+
#if defined(__ARM_NEON__)
QT_BEGIN_NAMESPACE
using namespace QImageScale;
+template<typename T>
+static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
+{
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
+ }
+#endif
+ scaleSection(0, dh);
+}
+
inline static uint32x4_t qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step)
{
uint32x2_t vpix32 = vmov_n_u32(*pix);
@@ -76,33 +71,36 @@ void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *d
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
-
- int xap = xapoints[x];
- if (xap > 0) {
- uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
-
- vx = vmulq_n_u32(vx, 256 - xap);
- vr = vmulq_n_u32(vr, xap);
- vx = vaddq_u32(vx, vr);
- vx = vshrq_n_u32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
+
+ vx = vmulq_n_u32(vx, 256 - xap);
+ vr = vmulq_n_u32(vr, xap);
+ vx = vaddq_u32(vx, vr);
+ vx = vshrq_n_u32(vx, 8);
+ }
+ vx = vshrq_n_u32(vx, 14);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = vshrq_n_u32(vx, 14);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template<bool RGB>
@@ -115,33 +113,36 @@ void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *d
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
-
- int yap = yapoints[y];
- if (yap > 0) {
- uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
-
- vx = vmulq_n_u32(vx, 256 - yap);
- vr = vmulq_n_u32(vr, yap);
- vx = vaddq_u32(vx, vr);
- vx = vshrq_n_u32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
+
+ vx = vmulq_n_u32(vx, 256 - yap);
+ vr = vmulq_n_u32(vr, yap);
+ vx = vaddq_u32(vx, vr);
+ vx = vshrq_n_u32(vx, 8);
+ }
+ vx = vshrq_n_u32(vx, 14);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = vshrq_n_u32(vx, 14);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template<bool RGB>
@@ -153,43 +154,46 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const int Cx = xapoints[x] >> 16;
- const int xap = xapoints[x] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
- vx = vshrq_n_u32(vx, 4);
- uint32x4_t vr = vmulq_n_u32(vx, yap);
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const int Cx = xapoints[x] >> 16;
+ const int xap = xapoints[x] & 0xffff;
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+ vx = vshrq_n_u32(vx, 4);
+ uint32x4_t vr = vmulq_n_u32(vx, yap);
+
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+ vx = vshrq_n_u32(vx, 4);
+ vx = vmulq_n_u32(vx, Cy);
+ vr = vaddq_u32(vr, vx);
+ }
sptr += sow;
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
vx = vshrq_n_u32(vx, 4);
- vx = vmulq_n_u32(vx, Cy);
+ vx = vmulq_n_u32(vx, j);
vr = vaddq_u32(vr, vx);
+
+ vx = vshrq_n_u32(vr, 24);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- sptr += sow;
- vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
- vx = vshrq_n_u32(vx, 4);
- vx = vmulq_n_u32(vx, j);
- vr = vaddq_u32(vr, vx);
-
- vx = vshrq_n_u32(vr, 24);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template void qt_qimageScaleAARGBA_up_x_down_y_neon<false>(QImageScaleInfo *isi, unsigned int *dest,
diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h
index 244d681718..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
@@ -66,6 +31,8 @@ namespace QImageScale {
int *xapoints{nullptr};
int *yapoints{nullptr};
int xup_yup{0};
+ int sh = 0;
+ int sw = 0;
};
}
diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp
index 5861a2e2ff..982e533a32 100644
--- a/src/gui/painting/qimagescale_sse4.cpp
+++ b/src/gui/painting/qimagescale_sse4.cpp
@@ -1,53 +1,48 @@
-/****************************************************************************
-**
-** 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/qdrawhelper_x86_p.h>
#include <private/qsimd_p.h>
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#include <private/qthreadpool_p.h>
+#endif
+
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
QT_BEGIN_NAMESPACE
using namespace QImageScale;
+template<typename T>
+static inline void multithread_pixels_function(QImageScaleInfo *isi, int dh, const T &scaleSection)
+{
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
+ }
+#endif
+ scaleSection(0, dh);
+}
+
inline static __m128i Q_DECL_VECTORCALL
qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step, const __m128i vxyap, const __m128i vCxy)
{
@@ -70,44 +65,47 @@ void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *d
int dw, int dh, int dow, int sow)
{
const unsigned int **ypoints = isi->ypoints;
- int *xpoints = isi->xpoints;
- int *xapoints = isi->xapoints;
- int *yapoints = isi->yapoints;
+ const int *xpoints = isi->xpoints;
+ const int *xapoints = isi->xapoints;
+ const int *yapoints = isi->yapoints;
const __m128i v256 = _mm_set1_epi32(256);
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
- const __m128i vCy = _mm_set1_epi32(Cy);
- const __m128i vyap = _mm_set1_epi32(yap);
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
-
- int xap = xapoints[x];
- if (xap > 0) {
- const __m128i vxap = _mm_set1_epi32(xap);
- const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
- __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
-
- vx = _mm_mullo_epi32(vx, vinvxap);
- vr = _mm_mullo_epi32(vr, vxap);
- vx = _mm_add_epi32(vx, vr);
- vx = _mm_srli_epi32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const int Cy = yapoints[y] >> 16;
+ const int yap = yapoints[y] & 0xffff;
+ const __m128i vCy = _mm_set1_epi32(Cy);
+ const __m128i vyap = _mm_set1_epi32(yap);
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
+
+ const int xap = xapoints[x];
+ if (xap > 0) {
+ const __m128i vxap = _mm_set1_epi32(xap);
+ const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
+ __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
+
+ vx = _mm_mullo_epi32(vx, vinvxap);
+ vr = _mm_mullo_epi32(vr, vxap);
+ vx = _mm_add_epi32(vx, vr);
+ vx = _mm_srli_epi32(vx, 8);
+ }
+ vx = _mm_srli_epi32(vx, 14);
+ vx = _mm_packus_epi32(vx, vx);
+ vx = _mm_packus_epi16(vx, vx);
+ *dptr = _mm_cvtsi128_si32(vx);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = _mm_srli_epi32(vx, 14);
- vx = _mm_packus_epi32(vx, _mm_setzero_si128());
- vx = _mm_packus_epi16(vx, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vx);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template<bool RGB>
@@ -122,37 +120,40 @@ void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *d
const __m128i v256 = _mm_set1_epi32(256);
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
- const __m128i vCx = _mm_set1_epi32(Cx);
- const __m128i vxap = _mm_set1_epi32(xap);
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
-
- int yap = yapoints[y];
- if (yap > 0) {
- const __m128i vyap = _mm_set1_epi32(yap);
- const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
- __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
-
- vx = _mm_mullo_epi32(vx, vinvyap);
- vr = _mm_mullo_epi32(vr, vyap);
- vx = _mm_add_epi32(vx, vr);
- vx = _mm_srli_epi32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+ const __m128i vCx = _mm_set1_epi32(Cx);
+ const __m128i vxap = _mm_set1_epi32(xap);
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ const __m128i vyap = _mm_set1_epi32(yap);
+ const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
+ __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
+
+ vx = _mm_mullo_epi32(vx, vinvyap);
+ vr = _mm_mullo_epi32(vr, vyap);
+ vx = _mm_add_epi32(vx, vr);
+ vx = _mm_srli_epi32(vx, 8);
+ }
+ vx = _mm_srli_epi32(vx, 14);
+ vx = _mm_packus_epi32(vx, vx);
+ vx = _mm_packus_epi16(vx, vx);
+ *dptr = _mm_cvtsi128_si32(vx);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = _mm_srli_epi32(vx, 14);
- vx = _mm_packus_epi32(vx, _mm_setzero_si128());
- vx = _mm_packus_epi16(vx, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vx);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template<bool RGB>
@@ -164,42 +165,45 @@ void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
- const __m128i vCy = _mm_set1_epi32(Cy);
- const __m128i vyap = _mm_set1_epi32(yap);
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const int Cx = xapoints[x] >> 16;
- const int xap = xapoints[x] & 0xffff;
- const __m128i vCx = _mm_set1_epi32(Cx);
- const __m128i vxap = _mm_set1_epi32(xap);
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
-
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+ const __m128i vCy = _mm_set1_epi32(Cy);
+ const __m128i vyap = _mm_set1_epi32(yap);
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const int Cx = xapoints[x] >> 16;
+ const int xap = xapoints[x] & 0xffff;
+ const __m128i vCx = _mm_set1_epi32(Cx);
+ const __m128i vxap = _mm_set1_epi32(xap);
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+ __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
+
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+ vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
+ }
sptr += sow;
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
+ vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
+
+ vr = _mm_srli_epi32(vr, 24);
+ vr = _mm_packus_epi32(vr, _mm_setzero_si128());
+ vr = _mm_packus_epi16(vr, _mm_setzero_si128());
+ *dptr = _mm_cvtsi128_si32(vr);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- sptr += sow;
- vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
-
- vr = _mm_srli_epi32(vr, 24);
- vr = _mm_packus_epi32(vr, _mm_setzero_si128());
- vr = _mm_packus_epi16(vr, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vr);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
- }
+ };
+ multithread_pixels_function(isi, dh, scaleSection);
}
template void qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(QImageScaleInfo *isi, unsigned int *dest,
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/qmatrix.cpp b/src/gui/painting/qmatrix.cpp
deleted file mode 100644
index b1f01332b6..0000000000
--- a/src/gui/painting/qmatrix.cpp
+++ /dev/null
@@ -1,1190 +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$
-**
-****************************************************************************/
-
-#include "qmatrix.h"
-
-#include "qdatastream.h"
-#include "qdebug.h"
-#include "qhashfunctions.h"
-#include "qregion.h"
-#include "qpainterpath.h"
-#include "qpainterpath_p.h"
-#include "qvariant.h"
-#include <qmath.h>
-
-#include <limits.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QMatrix
- \brief The QMatrix class specifies 2D transformations of a
- coordinate system.
- \obsolete
-
- \ingroup painting
- \inmodule QtGui
-
- A matrix specifies how to translate, scale, shear or rotate the
- coordinate system, and is typically used when rendering graphics.
- QMatrix, in contrast to QTransform, does not allow perspective
- transformations. QTransform is the recommended transformation
- class in Qt.
-
- A QMatrix object can be built using the setMatrix(), scale(),
- rotate(), translate() and shear() functions. Alternatively, it
- can be built by applying \l {QMatrix#Basic Matrix
- Operations}{basic matrix operations}. The matrix can also be
- defined when constructed, and it can be reset to the identity
- matrix (the default) using the reset() function.
-
- The QMatrix class supports mapping of graphic primitives: A given
- point, line, polygon, region, or painter path can be mapped to the
- coordinate system defined by \e this matrix using the map()
- function. In case of a rectangle, its coordinates can be
- transformed using the mapRect() function. A rectangle can also be
- transformed into a \e polygon (mapped to the coordinate system
- defined by \e this matrix), using the mapToPolygon() function.
-
- QMatrix provides the isIdentity() function which returns \c true if
- the matrix is the identity matrix, and the isInvertible() function
- which returns \c true if the matrix is non-singular (i.e. AB = BA =
- I). The inverted() function returns an inverted copy of \e this
- matrix if it is invertible (otherwise it returns the identity
- matrix). In addition, QMatrix provides the determinant() function
- returning the matrix's determinant.
-
- Finally, the QMatrix class supports matrix multiplication, and
- objects of the class can be streamed as well as compared.
-
- \tableofcontents
-
- \section1 Rendering Graphics
-
- When rendering graphics, the matrix defines the transformations
- but the actual transformation is performed by the drawing routines
- in QPainter.
-
- By default, QPainter operates on the associated device's own
- coordinate system. The standard coordinate system of a
- QPaintDevice has its origin located at the top-left position. The
- \e x values increase to the right; \e y values increase
- downward. For a complete description, see the \l {Coordinate
- System}{coordinate system} documentation.
-
- QPainter has functions to translate, scale, shear and rotate the
- coordinate system without using a QMatrix. For example:
-
- \table 100%
- \row
- \li \inlineimage qmatrix-simpletransformation.png
- \li
- \snippet matrix/matrix.cpp 0
- \endtable
-
- Although these functions are very convenient, it can be more
- efficient to build a QMatrix and call QPainter::setMatrix() if you
- want to perform more than a single transform operation. For
- example:
-
- \table 100%
- \row
- \li \inlineimage qmatrix-combinedtransformation.png
- \li
- \snippet matrix/matrix.cpp 1
- \endtable
-
- \section1 Basic Matrix Operations
-
- \image qmatrix-representation.png
-
- A QMatrix object contains a 3 x 3 matrix. The \c dx and \c dy
- elements specify horizontal and vertical translation. The \c m11
- and \c m22 elements specify horizontal and vertical scaling. And
- finally, the \c m21 and \c m12 elements specify horizontal and
- vertical \e shearing.
-
- QMatrix transforms a point in the plane to another point using the
- following formulas:
-
- \snippet code/src_gui_painting_qmatrix.cpp 0
-
- The point \e (x, y) is the original point, and \e (x', y') is the
- transformed point. \e (x', y') can be transformed back to \e (x,
- y) by performing the same operation on the inverted() matrix.
-
- The various matrix elements can be set when constructing the
- matrix, or by using the setMatrix() function later on. They can also
- be manipulated using the translate(), rotate(), scale() and
- shear() convenience functions, The currently set values can be
- retrieved using the m11(), m12(), m21(), m22(), dx() and dy()
- functions.
-
- Translation is the simplest transformation. Setting \c dx and \c
- dy will move the coordinate system \c dx units along the X axis
- and \c dy units along the Y axis. Scaling can be done by setting
- \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to
- 1.5 will double the height and increase the width by 50%. The
- identity matrix has \c m11 and \c m22 set to 1 (all others are set
- to 0) mapping a point to itself. Shearing is controlled by \c m12
- and \c m21. Setting these elements to values different from zero
- will twist the coordinate system. Rotation is achieved by
- carefully setting both the shearing factors and the scaling
- factors.
-
- Here's the combined transformations example using basic matrix
- operations:
-
- \table 100%
- \row
- \li \inlineimage qmatrix-combinedtransformation.png
- \li
- \snippet matrix/matrix.cpp 2
- \endtable
-
- \sa QPainter, QTransform, {Coordinate System},
- {painting/affine}{Affine Transformations Example}, {Transformations Example}
-*/
-
-
-// some defines to inline some code
-#define MAPDOUBLE(x, y, nx, ny) \
-{ \
- qreal fx = x; \
- qreal fy = y; \
- nx = _m11*fx + _m21*fy + _dx; \
- ny = _m12*fx + _m22*fy + _dy; \
-}
-
-#define MAPINT(x, y, nx, ny) \
-{ \
- qreal fx = x; \
- qreal fy = y; \
- nx = qRound(_m11*fx + _m21*fy + _dx); \
- ny = qRound(_m12*fx + _m22*fy + _dy); \
-}
-
-/*****************************************************************************
- QMatrix member functions
- *****************************************************************************/
-/*!
- \fn QMatrix::QMatrix(Qt::Initialization)
- \internal
-*/
-
-/*!
- Constructs an identity matrix.
-
- All elements are set to zero except \c m11 and \c m22 (specifying
- the scale), which are set to 1.
-
- \sa reset()
-*/
-
-QMatrix::QMatrix()
- : _m11(1.)
- , _m12(0.)
- , _m21(0.)
- , _m22(1.)
- , _dx(0.)
- , _dy(0.)
-{
-}
-
-/*!
- Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a
- m22, \a dx and \a dy.
-
- \sa setMatrix()
-*/
-
-QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
- : _m11(m11)
- , _m12(m12)
- , _m21(m21)
- , _m22(m22)
- , _dx(dx)
- , _dy(dy)
-{
-}
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-/*!
- Constructs a matrix that is a copy of the given \a matrix.
- */
-QMatrix::QMatrix(const QMatrix &matrix) noexcept
- : _m11(matrix._m11)
- , _m12(matrix._m12)
- , _m21(matrix._m21)
- , _m22(matrix._m22)
- , _dx(matrix._dx)
- , _dy(matrix._dy)
-{
-}
-#endif
-
-/*!
- Sets the matrix elements to the specified values, \a m11, \a m12,
- \a m21, \a m22, \a dx and \a dy.
-
- Note that this function replaces the previous values. QMatrix
- provide the translate(), rotate(), scale() and shear() convenience
- functions to manipulate the various matrix elements based on the
- currently defined coordinate system.
-
- \sa QMatrix()
-*/
-
-void QMatrix::setMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
-{
- _m11 = m11;
- _m12 = m12;
- _m21 = m21;
- _m22 = m22;
- _dx = dx;
- _dy = dy;
-}
-
-
-/*!
- \fn qreal QMatrix::m11() const
-
- Returns the horizontal scaling factor.
-
- \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-/*!
- \fn qreal QMatrix::m12() const
-
- Returns the vertical shearing factor.
-
- \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-/*!
- \fn qreal QMatrix::m21() const
-
- Returns the horizontal shearing factor.
-
- \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-/*!
- \fn qreal QMatrix::m22() const
-
- Returns the vertical scaling factor.
-
- \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-/*!
- \fn qreal QMatrix::dx() const
-
- Returns the horizontal translation factor.
-
- \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-/*!
- \fn qreal QMatrix::dy() const
-
- Returns the vertical translation factor.
-
- \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-
-
-/*!
- Maps the given coordinates \a x and \a y into the coordinate
- system defined by this matrix. The resulting values are put in *\a
- tx and *\a ty, respectively.
-
- The coordinates are transformed using the following formulas:
-
- \snippet code/src_gui_painting_qmatrix.cpp 1
-
- The point (x, y) is the original point, and (x', y') is the
- transformed point.
-
- \sa {QMatrix#Basic Matrix Operations}{Basic Matrix Operations}
-*/
-
-void QMatrix::map(qreal x, qreal y, qreal *tx, qreal *ty) const
-{
- MAPDOUBLE(x, y, *tx, *ty);
-}
-
-
-
-/*!
- \overload
-
- Maps the given coordinates \a x and \a y into the coordinate
- system defined by this matrix. The resulting values are put in *\a
- tx and *\a ty, respectively. Note that the transformed coordinates
- are rounded to the nearest integer.
-*/
-
-void QMatrix::map(int x, int y, int *tx, int *ty) const
-{
- MAPINT(x, y, *tx, *ty);
-}
-
-QRect QMatrix::mapRect(const QRect &rect) const
-{
- QRect result;
- if (_m12 == 0.0F && _m21 == 0.0F) {
- int x = qRound(_m11*rect.x() + _dx);
- int y = qRound(_m22*rect.y() + _dy);
- int w = qRound(_m11*rect.width());
- int h = qRound(_m22*rect.height());
- if (w < 0) {
- w = -w;
- x -= w;
- }
- if (h < 0) {
- h = -h;
- y -= h;
- }
- result = QRect(x, y, w, h);
- } else {
- // see mapToPolygon for explanations of the algorithm.
- qreal x0, y0;
- qreal x, y;
- MAPDOUBLE(rect.left(), rect.top(), x0, y0);
- qreal xmin = x0;
- qreal ymin = y0;
- qreal xmax = x0;
- qreal ymax = y0;
- MAPDOUBLE(rect.right() + 1, rect.top(), x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- MAPDOUBLE(rect.right() + 1, rect.bottom() + 1, x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- MAPDOUBLE(rect.left(), rect.bottom() + 1, x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- result = QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
- }
- return result;
-}
-
-/*!
- \fn QRectF QMatrix::mapRect(const QRectF &rectangle) const
-
- Creates and returns a QRectF object that is a copy of the given \a
- rectangle, mapped into the coordinate system defined by this
- matrix.
-
- The rectangle's coordinates are transformed using the following
- formulas:
-
- \snippet code/src_gui_painting_qmatrix.cpp 2
-
- If rotation or shearing has been specified, this function returns
- the \e bounding rectangle. To retrieve the exact region the given
- \a rectangle maps to, use the mapToPolygon() function instead.
-
- \sa mapToPolygon(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-QRectF QMatrix::mapRect(const QRectF &rect) const
-{
- QRectF result;
- if (_m12 == 0.0F && _m21 == 0.0F) {
- qreal x = _m11*rect.x() + _dx;
- qreal y = _m22*rect.y() + _dy;
- qreal w = _m11*rect.width();
- qreal h = _m22*rect.height();
- if (w < 0) {
- w = -w;
- x -= w;
- }
- if (h < 0) {
- h = -h;
- y -= h;
- }
- result = QRectF(x, y, w, h);
- } else {
- qreal x0, y0;
- qreal x, y;
- MAPDOUBLE(rect.x(), rect.y(), x0, y0);
- qreal xmin = x0;
- qreal ymin = y0;
- qreal xmax = x0;
- qreal ymax = y0;
- MAPDOUBLE(rect.x() + rect.width(), rect.y(), x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- MAPDOUBLE(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- MAPDOUBLE(rect.x(), rect.y() + rect.height(), x, y);
- xmin = qMin(xmin, x);
- ymin = qMin(ymin, y);
- xmax = qMax(xmax, x);
- ymax = qMax(ymax, y);
- result = QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
- }
- return result;
-}
-
-/*!
- \fn QRect QMatrix::mapRect(const QRect &rectangle) const
- \overload
-
- Creates and returns a QRect object that is a copy of the given \a
- rectangle, mapped into the coordinate system defined by this
- matrix. Note that the transformed coordinates are rounded to the
- nearest integer.
-*/
-
-
-/*!
- \fn QPoint operator*(const QPoint &point, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{point}).
-
- \sa QMatrix::map()
-*/
-
-QPoint QMatrix::map(const QPoint &p) const
-{
- qreal fx = p.x();
- qreal fy = p.y();
- return QPoint(qRound(_m11*fx + _m21*fy + _dx),
- qRound(_m12*fx + _m22*fy + _dy));
-}
-
-/*!
- \fn QPointF operator*(const QPointF &point, const QMatrix &matrix)
- \relates QMatrix
-
- Same as \a{matrix}.map(\a{point}).
-
- \sa QMatrix::map()
-*/
-
-/*!
- \overload
-
- Creates and returns a QPointF object that is a copy of the given
- \a point, mapped into the coordinate system defined by this
- matrix.
-*/
-QPointF QMatrix::map(const QPointF &point) const
-{
- qreal fx = point.x();
- qreal fy = point.y();
- return QPointF(_m11*fx + _m21*fy + _dx, _m12*fx + _m22*fy + _dy);
-}
-
-/*!
- \fn QPoint QMatrix::map(const QPoint &point) const
- \overload
-
- Creates and returns a QPoint object that is a copy of the given \a
- point, mapped into the coordinate system defined by this
- matrix. Note that the transformed coordinates are rounded to the
- nearest integer.
-*/
-
-/*!
- \fn QLineF operator*(const QLineF &line, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{line}).
-
- \sa QMatrix::map()
-*/
-
-/*!
- \fn QLine operator*(const QLine &line, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{line}).
-
- \sa QMatrix::map()
-*/
-
-/*!
- \overload
-
- Creates and returns a QLineF object that is a copy of the given \a
- line, mapped into the coordinate system defined by this matrix.
-*/
-QLineF QMatrix::map(const QLineF &line) const
-{
- return QLineF(map(line.p1()), map(line.p2()));
-}
-
-/*!
- \overload
-
- Creates and returns a QLine object that is a copy of the given \a
- line, mapped into the coordinate system defined by this matrix.
- Note that the transformed coordinates are rounded to the nearest
- integer.
-*/
-QLine QMatrix::map(const QLine &line) const
-{
- return QLine(map(line.p1()), map(line.p2()));
-}
-
-/*!
- \fn QPolygonF operator *(const QPolygonF &polygon, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{polygon}).
-
- \sa QMatrix::map()
-*/
-
-/*!
- \fn QPolygon operator*(const QPolygon &polygon, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{polygon}).
-
- \sa QMatrix::map()
-*/
-
-QPolygon QMatrix::map(const QPolygon &a) const
-{
- int size = a.size();
- int i;
- QPolygon p(size);
- const QPoint *da = a.constData();
- QPoint *dp = p.data();
- for(i = 0; i < size; i++) {
- MAPINT(da[i].x(), da[i].y(), dp[i].rx(), dp[i].ry());
- }
- return p;
-}
-
-/*!
- \fn QPolygonF QMatrix::map(const QPolygonF &polygon) const
- \overload
-
- Creates and returns a QPolygonF object that is a copy of the given
- \a polygon, mapped into the coordinate system defined by this
- matrix.
-*/
-QPolygonF QMatrix::map(const QPolygonF &a) const
-{
- int size = a.size();
- int i;
- QPolygonF p(size);
- const QPointF *da = a.constData();
- QPointF *dp = p.data();
- for(i = 0; i < size; i++) {
- MAPDOUBLE(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
- }
- return p;
-}
-
-/*!
- \fn QPolygon QMatrix::map(const QPolygon &polygon) const
- \overload
-
- Creates and returns a QPolygon object that is a copy of the given
- \a polygon, mapped into the coordinate system defined by this
- matrix. Note that the transformed coordinates are rounded to the
- nearest integer.
-*/
-
-/*!
- \fn QRegion operator*(const QRegion &region, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{region}).
-
- \sa QMatrix::map()
-*/
-
-extern QPainterPath qt_regionToPath(const QRegion &region);
-
-/*!
- \fn QRegion QMatrix::map(const QRegion &region) const
- \overload
-
- Creates and returns a QRegion object that is a copy of the given
- \a region, mapped into the coordinate system defined by this matrix.
-
- Calling this method can be rather expensive if rotations or
- shearing are used.
-*/
-QRegion QMatrix::map(const QRegion &r) const
-{
- if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { // translate or identity
- if (_dx == 0.0 && _dy == 0.0) // Identity
- return r;
- QRegion copy(r);
- copy.translate(qRound(_dx), qRound(_dy));
- return copy;
- }
-
- QPainterPath p = map(qt_regionToPath(r));
- return p.toFillPolygon().toPolygon();
-}
-
-/*!
- \fn QPainterPath operator *(const QPainterPath &path, const QMatrix &matrix)
- \relates QMatrix
-
- This is the same as \a{matrix}.map(\a{path}).
-
- \sa QMatrix::map()
-*/
-
-/*!
- \overload
-
- Creates and returns a QPainterPath object that is a copy of the
- given \a path, mapped into the coordinate system defined by this
- matrix.
-*/
-QPainterPath QMatrix::map(const QPainterPath &path) const
-{
- if (path.isEmpty())
- return QPainterPath();
-
- QPainterPath copy = path;
-
- // Translate or identity
- if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) {
-
- // Translate
- if (_dx != 0.0 || _dy != 0.0) {
- copy.detach();
- for (int i=0; i<path.elementCount(); ++i) {
- QPainterPath::Element &e = copy.d_ptr->elements[i];
- e.x += _dx;
- e.y += _dy;
- }
- }
-
- // Full xform
- } else {
- copy.detach();
- for (int i=0; i<path.elementCount(); ++i) {
- QPainterPath::Element &e = copy.d_ptr->elements[i];
- qreal fx = e.x, fy = e.y;
- e.x = _m11*fx + _m21*fy + _dx;
- e.y = _m12*fx + _m22*fy + _dy;
- }
- }
-
- return copy;
-}
-
-/*!
- \fn QPolygon QMatrix::mapToPolygon(const QRect &rectangle) const
-
- Creates and returns a QPolygon representation of the given \a
- rectangle, mapped into the coordinate system defined by this
- matrix.
-
- The rectangle's coordinates are transformed using the following
- formulas:
-
- \snippet code/src_gui_painting_qmatrix.cpp 3
-
- Polygons and rectangles behave slightly differently when
- transformed (due to integer rounding), so
- \c{matrix.map(QPolygon(rectangle))} is not always the same as
- \c{matrix.mapToPolygon(rectangle)}.
-
- \sa mapRect(), {QMatrix#Basic Matrix Operations}{Basic Matrix
- Operations}
-*/
-QPolygon QMatrix::mapToPolygon(const QRect &rect) const
-{
- QPolygon a(4);
- qreal x[4], y[4];
- if (_m12 == 0.0F && _m21 == 0.0F) {
- x[0] = _m11*rect.x() + _dx;
- y[0] = _m22*rect.y() + _dy;
- qreal w = _m11*rect.width();
- qreal h = _m22*rect.height();
- if (w < 0) {
- w = -w;
- x[0] -= w;
- }
- if (h < 0) {
- h = -h;
- y[0] -= h;
- }
- x[1] = x[0]+w;
- x[2] = x[1];
- x[3] = x[0];
- y[1] = y[0];
- y[2] = y[0]+h;
- y[3] = y[2];
- } else {
- qreal right = rect.x() + rect.width();
- qreal bottom = rect.y() + rect.height();
- MAPDOUBLE(rect.x(), rect.y(), x[0], y[0]);
- MAPDOUBLE(right, rect.y(), x[1], y[1]);
- MAPDOUBLE(right, bottom, x[2], y[2]);
- MAPDOUBLE(rect.x(), bottom, x[3], y[3]);
- }
-#if 0
- int i;
- for(i = 0; i< 4; i++)
- qDebug("coords(%d) = (%f/%f) (%d/%d)", i, x[i], y[i], qRound(x[i]), qRound(y[i]));
- qDebug("width=%f, height=%f", qSqrt((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0])),
- qSqrt((x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3])));
-#endif
- // all coordinates are correctly, tranform to a pointarray
- // (rounding to the next integer)
- a.setPoints(4, qRound(x[0]), qRound(y[0]),
- qRound(x[1]), qRound(y[1]),
- qRound(x[2]), qRound(y[2]),
- qRound(x[3]), qRound(y[3]));
- return a;
-}
-
-/*!
- Resets the matrix to an identity matrix, i.e. all elements are set
- to zero, except \c m11 and \c m22 (specifying the scale) which are
- set to 1.
-
- \sa QMatrix(), isIdentity(), {QMatrix#Basic Matrix
- Operations}{Basic Matrix Operations}
-*/
-
-void QMatrix::reset()
-{
- _m11 = _m22 = 1.0;
- _m12 = _m21 = _dx = _dy = 0.0;
-}
-
-/*!
- \fn bool QMatrix::isIdentity() const
-
- Returns \c true if the matrix is the identity matrix, otherwise
- returns \c false.
-
- \sa reset()
-*/
-
-/*!
- Moves the coordinate system \a dx along the x axis and \a dy along
- the y axis, and returns a reference to the matrix.
-
- \sa setMatrix()
-*/
-
-QMatrix &QMatrix::translate(qreal dx, qreal dy)
-{
- _dx += dx*_m11 + dy*_m21;
- _dy += dy*_m22 + dx*_m12;
- return *this;
-}
-
-/*!
- \fn QMatrix &QMatrix::scale(qreal sx, qreal sy)
-
- Scales the coordinate system by \a sx horizontally and \a sy
- vertically, and returns a reference to the matrix.
-
- \sa setMatrix()
-*/
-
-QMatrix &QMatrix::scale(qreal sx, qreal sy)
-{
- _m11 *= sx;
- _m12 *= sx;
- _m21 *= sy;
- _m22 *= sy;
- return *this;
-}
-
-/*!
- Shears the coordinate system by \a sh horizontally and \a sv
- vertically, and returns a reference to the matrix.
-
- \sa setMatrix()
-*/
-
-QMatrix &QMatrix::shear(qreal sh, qreal sv)
-{
- qreal tm11 = sv*_m21;
- qreal tm12 = sv*_m22;
- qreal tm21 = sh*_m11;
- qreal tm22 = sh*_m12;
- _m11 += tm11;
- _m12 += tm12;
- _m21 += tm21;
- _m22 += tm22;
- return *this;
-}
-
-const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
-
-/*!
- \fn QMatrix &QMatrix::rotate(qreal degrees)
-
- Rotates the coordinate system the given \a degrees
- counterclockwise.
-
- Note that if you apply a QMatrix to a point defined in widget
- coordinates, the direction of the rotation will be clockwise
- because the y-axis points downwards.
-
- Returns a reference to the matrix.
-
- \sa setMatrix()
-*/
-
-QMatrix &QMatrix::rotate(qreal a)
-{
- qreal sina = 0;
- qreal cosa = 0;
- if (a == 90. || a == -270.)
- sina = 1.;
- else if (a == 270. || a == -90.)
- sina = -1.;
- else if (a == 180.)
- cosa = -1.;
- else{
- qreal b = deg2rad*a; // convert to radians
- sina = qSin(b); // fast and convenient
- cosa = qCos(b);
- }
- qreal tm11 = cosa*_m11 + sina*_m21;
- qreal tm12 = cosa*_m12 + sina*_m22;
- qreal tm21 = -sina*_m11 + cosa*_m21;
- qreal tm22 = -sina*_m12 + cosa*_m22;
- _m11 = tm11; _m12 = tm12;
- _m21 = tm21; _m22 = tm22;
- return *this;
-}
-
-/*!
- \fn bool QMatrix::isInvertible() const
-
- Returns \c true if the matrix is invertible, otherwise returns \c false.
-
- \sa inverted()
-*/
-
-/*!
- \since 4.6
- \fn qreal QMatrix::determinant() const
-
- Returns the matrix's determinant.
-*/
-
-/*!
- Returns an inverted copy of this matrix.
-
- If the matrix is singular (not invertible), the returned matrix is
- the identity matrix. If \a invertible is valid (i.e. not 0), its
- value is set to true if the matrix is invertible, otherwise it is
- set to false.
-
- \sa isInvertible()
-*/
-
-QMatrix QMatrix::inverted(bool *invertible) const
-{
- qreal dtr = determinant();
- if (dtr == 0.0) {
- if (invertible)
- *invertible = false; // singular matrix
- return QMatrix(true);
- }
- else { // invertible matrix
- if (invertible)
- *invertible = true;
- qreal dinv = 1.0/dtr;
- return QMatrix((_m22*dinv), (-_m12*dinv),
- (-_m21*dinv), (_m11*dinv),
- ((_m21*_dy - _m22*_dx)*dinv),
- ((_m12*_dx - _m11*_dy)*dinv),
- true);
- }
-}
-
-
-/*!
- \fn bool QMatrix::operator==(const QMatrix &matrix) const
-
- Returns \c true if this matrix is equal to the given \a matrix,
- otherwise returns \c false.
-*/
-
-bool QMatrix::operator==(const QMatrix &m) const
-{
- return _m11 == m._m11 &&
- _m12 == m._m12 &&
- _m21 == m._m21 &&
- _m22 == m._m22 &&
- _dx == m._dx &&
- _dy == m._dy;
-}
-
-
-/*!
- \since 5.6
- \relates QMatrix
-
- Returns the hash value for \a key, using
- \a seed to seed the calculation.
-*/
-uint qHash(const QMatrix &key, uint seed) noexcept
-{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, key.m11());
- seed = hash(seed, key.m12());
- seed = hash(seed, key.m21());
- seed = hash(seed, key.m22());
- seed = hash(seed, key.dx());
- seed = hash(seed, key.dy());
- return seed;
-}
-
-/*!
- \fn bool QMatrix::operator!=(const QMatrix &matrix) const
-
- Returns \c true if this matrix is not equal to the given \a matrix,
- otherwise returns \c false.
-*/
-
-bool QMatrix::operator!=(const QMatrix &m) const
-{
- return _m11 != m._m11 ||
- _m12 != m._m12 ||
- _m21 != m._m21 ||
- _m22 != m._m22 ||
- _dx != m._dx ||
- _dy != m._dy;
-}
-
-/*!
- \fn QMatrix &QMatrix::operator *=(const QMatrix &matrix)
- \overload
-
- Returns the result of multiplying this matrix by the given \a
- matrix.
-*/
-
-QMatrix &QMatrix::operator *=(const QMatrix &m)
-{
- qreal tm11 = _m11*m._m11 + _m12*m._m21;
- qreal tm12 = _m11*m._m12 + _m12*m._m22;
- qreal tm21 = _m21*m._m11 + _m22*m._m21;
- qreal tm22 = _m21*m._m12 + _m22*m._m22;
-
- qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx;
- qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy;
-
- _m11 = tm11; _m12 = tm12;
- _m21 = tm21; _m22 = tm22;
- _dx = tdx; _dy = tdy;
- return *this;
-}
-
-/*!
- \fn QMatrix QMatrix::operator *(const QMatrix &matrix) const
-
- Returns the result of multiplying this matrix by the given \a
- matrix.
-
- Note that matrix multiplication is not commutative, i.e. a*b !=
- b*a.
-*/
-
-QMatrix QMatrix::operator *(const QMatrix &m) const
-{
- qreal tm11 = _m11*m._m11 + _m12*m._m21;
- qreal tm12 = _m11*m._m12 + _m12*m._m22;
- qreal tm21 = _m21*m._m11 + _m22*m._m21;
- qreal tm22 = _m21*m._m12 + _m22*m._m22;
-
- qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx;
- qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy;
- return QMatrix(tm11, tm12, tm21, tm22, tdx, tdy, true);
-}
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-/*!
- Assigns the given \a matrix's values to this matrix.
-*/
-QMatrix &QMatrix::operator=(const QMatrix &matrix) noexcept
-{
- _m11 = matrix._m11;
- _m12 = matrix._m12;
- _m21 = matrix._m21;
- _m22 = matrix._m22;
- _dx = matrix._dx;
- _dy = matrix._dy;
- return *this;
-}
-#endif
-
-/*!
- \since 4.2
-
- Returns the matrix as a QVariant.
-*/
-QMatrix::operator QVariant() const
-{
- return QVariant(QVariant::Matrix, this);
-}
-
-Q_GUI_EXPORT QPainterPath operator *(const QPainterPath &p, const QMatrix &m)
-{
- return m.map(p);
-}
-
-
-/*****************************************************************************
- QMatrix stream functions
- *****************************************************************************/
-#ifndef QT_NO_DATASTREAM
-/*!
- \fn QDataStream &operator<<(QDataStream &stream, const QMatrix &matrix)
- \relates QMatrix
-
- Writes the given \a matrix to the given \a stream and returns a
- reference to the stream.
-
- \sa {Serializing Qt Data Types}
-*/
-
-QDataStream &operator<<(QDataStream &s, const QMatrix &m)
-{
- if (s.version() == 1) {
- s << (float)m.m11() << (float)m.m12() << (float)m.m21()
- << (float)m.m22() << (float)m.dx() << (float)m.dy();
- } else {
- s << double(m.m11())
- << double(m.m12())
- << double(m.m21())
- << double(m.m22())
- << double(m.dx())
- << double(m.dy());
- }
- return s;
-}
-
-/*!
- \fn QDataStream &operator>>(QDataStream &stream, QMatrix &matrix)
- \relates QMatrix
-
- Reads the given \a matrix from the given \a stream and returns a
- reference to the stream.
-
- \sa {Serializing Qt Data Types}
-*/
-
-QDataStream &operator>>(QDataStream &s, QMatrix &m)
-{
- if (s.version() == 1) {
- float m11, m12, m21, m22, dx, dy;
- s >> m11; s >> m12; s >> m21; s >> m22;
- s >> dx; s >> dy;
- m.setMatrix(m11, m12, m21, m22, dx, dy);
- }
- else {
- double m11, m12, m21, m22, dx, dy;
- s >> m11;
- s >> m12;
- s >> m21;
- s >> m22;
- s >> dx;
- s >> dy;
- m.setMatrix(m11, m12, m21, m22, dx, dy);
- }
- return s;
-}
-#endif // QT_NO_DATASTREAM
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug dbg, const QMatrix &m)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QMatrix("
- << "11=" << m.m11()
- << " 12=" << m.m12()
- << " 21=" << m.m21()
- << " 22=" << m.m22()
- << " dx=" << m.dx()
- << " dy=" << m.dy()
- << ')';
- return dbg;
-}
-#endif
-
-/*!
- \fn bool qFuzzyCompare(const QMatrix& m1, const QMatrix& m2)
-
- \relates QMatrix
- \since 4.6
-
- \brief The qFuzzyCompare function is for comparing two matrices
- using a fuzziness factor.
-
- Returns \c true if \a m1 and \a m2 are equal, allowing for a small
- fuzziness factor for floating-point comparisons; false otherwise.
-*/
-
-QT_END_NAMESPACE
diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h
deleted file mode 100644
index a167260ade..0000000000
--- a/src/gui/painting/qmatrix.h
+++ /dev/null
@@ -1,194 +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 QMATRIX_H
-#define QMATRIX_H
-
-#include <QtGui/qtguiglobal.h>
-#include <QtGui/qpolygon.h>
-#include <QtGui/qregion.h>
-#include <QtGui/qwindowdefs.h>
-#include <QtCore/qline.h>
-#include <QtCore/qpoint.h>
-#include <QtCore/qrect.h>
-
-QT_BEGIN_NAMESPACE
-
-
-class QPainterPath;
-class QVariant;
-
-class Q_GUI_EXPORT QMatrix // 2D transform matrix
-{
-public:
- inline explicit QMatrix(Qt::Initialization) {}
- QMatrix();
- QMatrix(qreal m11, qreal m12, qreal m21, qreal m22,
- qreal dx, qreal dy);
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- // ### Qt 6: remove; the compiler-generated ones are fine!
- QMatrix &operator=(QMatrix &&other) noexcept // = default
- { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QMatrix)); return *this; }
- QMatrix &operator=(const QMatrix &) noexcept; // = default
- QMatrix(QMatrix &&other) noexcept // = default
- { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QMatrix)); }
- QMatrix(const QMatrix &other) noexcept; // = default
-#endif
-
- void setMatrix(qreal m11, qreal m12, qreal m21, qreal m22,
- qreal dx, qreal dy);
-
- qreal m11() const { return _m11; }
- qreal m12() const { return _m12; }
- qreal m21() const { return _m21; }
- qreal m22() const { return _m22; }
- qreal dx() const { return _dx; }
- qreal dy() const { return _dy; }
-
- void map(int x, int y, int *tx, int *ty) const;
- void map(qreal x, qreal y, qreal *tx, qreal *ty) const;
- QRect mapRect(const QRect &) const;
- QRectF mapRect(const QRectF &) const;
-
- QPoint map(const QPoint &p) const;
- QPointF map(const QPointF&p) const;
- QLine map(const QLine &l) const;
- QLineF map(const QLineF &l) const;
- QPolygonF map(const QPolygonF &a) const;
- QPolygon map(const QPolygon &a) const;
- QRegion map(const QRegion &r) const;
- QPainterPath map(const QPainterPath &p) const;
- QPolygon mapToPolygon(const QRect &r) const;
-
- void reset();
- inline bool isIdentity() const;
-
- QMatrix &translate(qreal dx, qreal dy);
- QMatrix &scale(qreal sx, qreal sy);
- QMatrix &shear(qreal sh, qreal sv);
- QMatrix &rotate(qreal a);
-
- bool isInvertible() const { return !qFuzzyIsNull(_m11*_m22 - _m12*_m21); }
- qreal determinant() const { return _m11*_m22 - _m12*_m21; }
-
- Q_REQUIRED_RESULT QMatrix inverted(bool *invertible = nullptr) const;
-
- bool operator==(const QMatrix &) const;
- bool operator!=(const QMatrix &) const;
-
- QMatrix &operator*=(const QMatrix &);
- QMatrix operator*(const QMatrix &o) const;
-
- operator QVariant() const;
-
-private:
- inline QMatrix(bool)
- : _m11(1.)
- , _m12(0.)
- , _m21(0.)
- , _m22(1.)
- , _dx(0.)
- , _dy(0.) {}
- inline QMatrix(qreal am11, qreal am12, qreal am21, qreal am22, qreal adx, qreal ady, bool)
- : _m11(am11)
- , _m12(am12)
- , _m21(am21)
- , _m22(am22)
- , _dx(adx)
- , _dy(ady) {}
- friend class QTransform;
- qreal _m11, _m12;
- qreal _m21, _m22;
- qreal _dx, _dy;
-};
-Q_DECLARE_TYPEINFO(QMatrix, Q_MOVABLE_TYPE);
-
-Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QMatrix &key, uint seed = 0) noexcept;
-
-// mathematical semantics
-inline QPoint operator*(const QPoint &p, const QMatrix &m)
-{ return m.map(p); }
-inline QPointF operator*(const QPointF &p, const QMatrix &m)
-{ return m.map(p); }
-inline QLineF operator*(const QLineF &l, const QMatrix &m)
-{ return m.map(l); }
-inline QLine operator*(const QLine &l, const QMatrix &m)
-{ return m.map(l); }
-inline QPolygon operator *(const QPolygon &a, const QMatrix &m)
-{ return m.map(a); }
-inline QPolygonF operator *(const QPolygonF &a, const QMatrix &m)
-{ return m.map(a); }
-inline QRegion operator *(const QRegion &r, const QMatrix &m)
-{ return m.map(r); }
-Q_GUI_EXPORT QPainterPath operator *(const QPainterPath &p, const QMatrix &m);
-
-inline bool QMatrix::isIdentity() const
-{
- return qFuzzyIsNull(_m11 - 1) && qFuzzyIsNull(_m22 - 1) && qFuzzyIsNull(_m12)
- && qFuzzyIsNull(_m21) && qFuzzyIsNull(_dx) && qFuzzyIsNull(_dy);
-}
-
-inline bool qFuzzyCompare(const QMatrix& m1, const QMatrix& m2)
-{
- return qFuzzyCompare(m1.m11(), m2.m11())
- && qFuzzyCompare(m1.m12(), m2.m12())
- && qFuzzyCompare(m1.m21(), m2.m21())
- && qFuzzyCompare(m1.m22(), m2.m22())
- && qFuzzyCompare(m1.dx(), m2.dx())
- && qFuzzyCompare(m1.dy(), m2.dy());
-}
-
-
-/*****************************************************************************
- QMatrix stream functions
- *****************************************************************************/
-
-#ifndef QT_NO_DATASTREAM
-Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QMatrix &);
-Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QMatrix &);
-#endif
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QMatrix &);
-#endif
-
-QT_END_NAMESPACE
-
-#endif // QMATRIX_H
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 685fbbb37a..9752069931 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -1,54 +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$
-**
-****************************************************************************/
-
-#include "private/qmemrotate_p.h"
+// 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"
QT_BEGIN_NAMESPACE
static const int tileSize = 32;
-template <class T>
-static
-inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
+template<class T>
+static inline void qt_memrotate90_tiled(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
+ const qsizetype sstride = isstride / sizeof(T);
+ const qsizetype dstride = idstride / sizeof(T);
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
@@ -102,11 +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;
@@ -130,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 =
@@ -189,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;
@@ -225,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)
+template<class T>
+static inline void qt_memrotate180_template(const T *src, int w, int h, int isstride, T *dest, int idstride)
{
- // packed algorithm doesn't have any benefit for quint32
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
+ const qsizetype sstride = isstride;
+ const qsizetype dstride = idstride;
-template <>
-inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
-{
- qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
-}
-
-template <class T>
-static
-inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
-{
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);
@@ -267,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) \
@@ -321,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)
@@ -403,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
{
@@ -414,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 677fd57af9..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
@@ -52,7 +16,7 @@
//
#include <QtGui/private/qtguiglobal_p.h>
-#include "private/qdrawhelper_p.h"
+#include <QtGui/private/qdrawhelper_p.h>
QT_BEGIN_NAMESPACE
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 3fdd0206b7..4dc5f035e6 100644
--- a/src/gui/painting/qpagedpaintdevice.cpp
+++ b/src/gui/painting/qpagedpaintdevice.cpp
@@ -1,86 +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()
-{
-}
+
+QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate() = default;
/*!
\class QPagedPaintDevice
@@ -95,15 +22,6 @@ QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate()
QPdfWriter and QPrinter inherit from it.
*/
-/*!
- Constructs a new paged paint device.
-
- \deprecated
- */
-QPagedPaintDevice::QPagedPaintDevice()
- : d(new QDummyPagedPaintDevicePrivate)
-{
-}
/*!
\internal
@@ -132,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.
@@ -296,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.
@@ -420,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.
@@ -435,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
@@ -464,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.
@@ -494,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 3a43bd7828..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
@@ -60,9 +24,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate
{
public:
QPagedPaintDevicePrivate()
- : fromPage(0),
- toPage(0),
- pageOrderAscending(true),
+ : pageOrderAscending(true),
printSelectionOnly(false)
{
}
@@ -83,8 +45,7 @@ public:
static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; }
// These are currently required to keep QPrinter functionality working in QTextDocument::print()
- int fromPage;
- int toPage;
+ 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 d73a66b790..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"},
@@ -385,7 +355,8 @@ static const StandardPageSize qt_pageSizes[] = {
};
static const int pageSizesCount = int(sizeof(qt_pageSizes) / sizeof(qt_pageSizes[0]));
-Q_STATIC_ASSERT(pageSizesCount == QPageSize::LastPageSize + 1);
+static_assert(pageSizesCount == QPageSize::LastPageSize + 1);
+static_assert(QPageSize::LastPageSize < 256);
// Return key name for PageSize
static QString qt_keyForPageSizeId(QPageSize::PageSizeId id)
@@ -398,14 +369,14 @@ static QPageSize::PageSizeId qt_idForPpdKey(const QString &ppdKey, QSize *match
{
if (ppdKey.isEmpty())
return QPageSize::Custom;
- QStringRef key(&ppdKey);
+ 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..221863aad7 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,14 +196,16 @@ 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); }
+#if QT_GUI_REMOVED_SINCE(6, 4)
friend Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs);
+#endif
bool isEquivalentTo(const QPageSize &other) const;
bool isValid() const;
@@ -287,6 +249,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 +264,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 0cba864523..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
@@ -39,8 +15,7 @@
right and Y increases downwards. The unit is one pixel.
The drawing capabilities of QPaintDevice are currently implemented
- by the QWidget, QImage, QPixmap, QGLPixelBuffer, QPicture, and
- QPrinter subclasses.
+ by the QWidget, QImage, QPixmap, QPicture, and QPrinter subclasses.
To implement support for a new backend, you must derive from
QPaintDevice and reimplement the virtual paintEngine() function to
@@ -124,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()
*/
/*!
@@ -285,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 1785fcd12d..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
@@ -158,7 +126,7 @@ QFont QTextItem::font() const
X11 and \macos, it is the backend for painting on QImage and it is
used as a fallback for paint engines that do not support a certain
capability. In addition we provide QPaintEngine implementations for
- OpenGL (accessible through QGLWidget) and printing (which allows using
+ OpenGL (accessible through QOpenGLWidget) and printing (which allows using
QPainter to draw on a QPrinter object).
If one wants to use QPainter to draw to a different backend,
@@ -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 9fb67e253e..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());
@@ -273,7 +239,6 @@ public:
QBrush backgroundBrush() const;
Qt::BGMode backgroundMode() const;
QFont font() const;
- QMatrix matrix() const;
QTransform transform() const;
Qt::ClipOperation clipOperation() const;
@@ -319,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) {
@@ -330,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 bc65ed56e3..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,13 +21,14 @@
#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>
#include <private/qcosmeticstroker_p.h>
-#include "qmemrotate_p.h"
-#include "qrgba64_p.h"
+#include <private/qdrawhelper_p.h>
+#include <private/qmemrotate_p.h>
+#include <private/qpixellayout_p.h>
+#include <private/qrgba64_p.h>
#include "qpaintengine_raster_p.h"
// #include "qbezier_p.h"
@@ -133,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; }
@@ -150,15 +114,10 @@ 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()
{
-#ifdef Q_OS_WINRT
- return false;
-#else // Q_OS_WINRT
UINT result = 0;
#if !defined(SPI_GETFONTSMOOTHINGTYPE) // MinGW
# define SPI_GETFONTSMOOTHINGTYPE 0x200A
@@ -166,7 +125,6 @@ static inline bool winClearTypeFontsEnabled()
#endif
SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
return result == FE_FONTSMOOTHINGCLEARTYPE;
-#endif // !Q_OS_WINRT
}
/*!
@@ -185,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
{
@@ -273,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)
@@ -311,8 +240,7 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
/*!
\class QRasterPaintEngine
- \preliminary
- \ingroup qws
+ \internal
\inmodule QtGui
\since 4.2
@@ -341,21 +269,12 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
\sa QPaintEngine
*/
-/*!
- \fn Type QRasterPaintEngine::type() const
+/*
+ \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
@@ -486,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;
@@ -560,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();
@@ -611,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;
@@ -718,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) {
@@ -743,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...
@@ -763,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)
@@ -817,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());
@@ -844,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;
@@ -903,28 +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);
-#if QT_DEPRECATED_SINCE(5, 14)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- if (s->renderHints & QPainter::HighQualityAntialiasing)
- s->flags.antialiased = true;
-QT_WARNING_POP
-#endif
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();
}
/*!
@@ -1012,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());
@@ -1082,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());
@@ -1260,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;
}
}
@@ -1319,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;
}
@@ -1329,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) {
@@ -1514,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);
@@ -1566,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;
@@ -1585,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);
@@ -1632,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);
@@ -1666,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())
@@ -1697,24 +1581,28 @@ 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(),
s->lastPen.capStyle() == Qt::SquareCap);
} else {
- d->rasterizeLine_dashed(line, width,
- &dashIndex, &dashOffset, &inDash);
+ // LinesHint means each line is distinct, so restart dashing
+ int dIndex = dashIndex;
+ qreal dOffset = dashOffset;
+ bool inD = inDash;
+ d->rasterizeLine_dashed(line, width, &dIndex, &dOffset, &inD);
}
}
}
@@ -1724,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);
@@ -1788,9 +1672,9 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
// ### Optimize for non transformed ellipses and rectangles...
QRectF cpRect = path.controlPointRect();
- const QRect pathDeviceRect = s->matrix.mapRect(cpRect).toRect();
+ const QRectF pathDeviceRect = s->matrix.mapRect(cpRect);
// Skip paths that by conservative estimates are completely outside the paint device.
- if (!pathDeviceRect.intersects(d->deviceRect))
+ if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid())
return;
ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData);
@@ -1867,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
*/
@@ -1878,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;
}
@@ -1894,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);
@@ -1917,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;
@@ -1958,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);
@@ -2014,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);
@@ -2079,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);
@@ -2324,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()) {
@@ -2346,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();
@@ -2369,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())) {
@@ -2411,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);
@@ -2444,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;
@@ -2483,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());
@@ -2498,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 {
@@ -2591,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);
@@ -2649,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();
@@ -2688,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;
}
@@ -2730,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;
}
@@ -2758,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;
@@ -2871,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
@@ -2881,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)
@@ -2906,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());
}
@@ -2917,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();
@@ -2940,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,
@@ -3012,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()
@@ -3028,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);
@@ -3049,7 +2964,12 @@ bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
int penWidth) const
{
- return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
+ const QRectF norm = rect.normalized();
+ 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;
+ return isUnclipped(norm.toAlignedRect(), penWidth);
}
inline ProcessSpans
@@ -3079,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
{
- QFixed clipLeft = QFixed::fromReal(clip.left());
- QFixed clipRight = QFixed::fromReal(clip.right());
- QFixed clipTop = QFixed::fromReal(clip.top());
- QFixed clipBottom = QFixed::fromReal(clip.bottom());
+ 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() - 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) {
@@ -3109,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};
}
/*!
@@ -3135,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);
@@ -3158,7 +3084,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
#ifdef QT_DEBUG_DRAW
Q_D(QRasterPaintEngine);
fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
- p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
+ p.x(), p.y(), QStringView(ti.chars, ti.num_chars).toLatin1().data(),
d->glyphCacheFormat);
#endif
@@ -3190,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);
@@ -3228,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);
}
@@ -3248,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);
}
@@ -3269,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());
@@ -3290,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)
@@ -3301,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;
@@ -3341,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());
@@ -3463,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;
@@ -3567,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);
@@ -3579,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)
@@ -3588,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;
@@ -3653,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);
@@ -3734,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);
@@ -3774,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);
}
@@ -3792,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;
@@ -3801,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;
}
@@ -3830,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]);
}
@@ -3868,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();
@@ -3906,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;
@@ -3930,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) {
@@ -3942,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;
@@ -4083,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) {
@@ -4146,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;
@@ -4176,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) {
@@ -4201,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;
}
@@ -4210,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);
@@ -4219,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);
@@ -4227,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);
@@ -4244,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;
}
}
@@ -4269,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) {}
@@ -4280,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();
@@ -4312,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;
@@ -4331,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);
@@ -4537,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();
@@ -4545,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;
}
@@ -4559,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);
@@ -4583,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);
@@ -4611,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);
@@ -4644,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;
@@ -4910,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
@@ -4931,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 089aadc3f7..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;
}
@@ -434,14 +398,14 @@ public:
QImage::Format prepare(QImage *image);
- uchar *scanLine(int y) { Q_ASSERT(y>=0); Q_ASSERT(y<m_height); return m_buffer + y * qsizetype(bytes_per_line); }
+ uchar *scanLine(int y) { Q_ASSERT(y>=0); Q_ASSERT(y<m_height); return m_buffer + y * bytes_per_line; }
int width() const { return m_width; }
int height() const { return m_height; }
- int bytesPerLine() const { return bytes_per_line; }
+ qsizetype bytesPerLine() const { return bytes_per_line; }
int bytesPerPixel() const { return bytes_per_pixel; }
template<typename T>
- int stride() { return bytes_per_line / sizeof(T); }
+ int stride() { return static_cast<int>(bytes_per_line / sizeof(T)); }
uchar *buffer() const { return m_buffer; }
@@ -451,12 +415,13 @@ public:
QPainter::CompositionMode compositionMode;
QImage::Format format;
+ QColorSpace colorSpace;
QImage colorizeBitmap(const QImage &image, const QColor &color);
private:
int m_width;
int m_height;
- int bytes_per_line;
+ qsizetype bytes_per_line;
int bytes_per_pixel;
uchar *m_buffer;
};
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 f70bbbd7d2..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
@@ -96,10 +67,15 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
QTextItem::RenderFlags flags, qreal width,
const QTextCharFormat &charFormat);
// Helper function to calculate left most position, width and flags for decoration drawing
-Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
- const QFixedPoint *positions, int glyphCount,
- QFontEngine *fontEngine, const QFont &font,
- const QTextCharFormat &charFormat);
+static void qt_draw_decoration_for_glyphs(QPainter *painter,
+ const QPointF &decorationPosition,
+ const glyph_t *glyphArray,
+ const QFixedPoint *positions,
+ int glyphCount,
+ QFontEngine *fontEngine,
+ bool underline,
+ bool overline,
+ bool strikeOut);
static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
{
@@ -175,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);
@@ -182,44 +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);
- delete dummyState;
}
+QPainterPrivate::~QPainterPrivate()
+ = default;
QTransform QPainterPrivate::viewTransform() const
{
@@ -238,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
@@ -263,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);
@@ -321,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)
@@ -330,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;
}
}
@@ -410,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;
@@ -1154,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
@@ -1231,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.
@@ -1404,8 +1373,7 @@ void QPainterPrivate::updateState(QPainterState *newState)
cases where expensive operations are ok to use, for instance when
the result is cached in a QPixmap.
- \sa QPaintDevice, QPaintEngine, {Qt SVG}, {Basic Drawing Example},
- {Drawing Utility Functions}
+ \sa QPaintDevice, QPaintEngine, {Qt SVG}, {Basic Drawing Example}, {<qdrawutil.h>}{Drawing Utility Functions}
*/
/*!
@@ -1426,16 +1394,15 @@ void QPainterPrivate::updateState(QPainterState *newState)
a smooth pixmap transformation algorithm (such as bilinear) rather
than nearest neighbor.
- \value HighQualityAntialiasing This value is obsolete and will be ignored,
- use the Antialiasing render hint instead.
-
- \value NonCosmeticDefaultPen This value is obsolete, the default for QPen
- is now non-cosmetic.
-
- \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
@@ -1444,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}
*/
@@ -1514,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);
}
}
@@ -1544,25 +1515,8 @@ QPaintDevice *QPainter::device() const
bool QPainter::isActive() const
{
Q_D(const QPainter);
- return d->engine;
-}
-
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- Initializes the painters pen, background and font to the same as
- the given \a device.
-
- \obsolete
-
- \sa begin(), {QPainter#Settings}{Settings}
-*/
-void QPainter::initFrom(const QPaintDevice *device)
-{
- Q_ASSERT_X(device, "QPainter::initFrom(const QPaintDevice *device)", "QPaintDevice cannot be 0");
- Q_D(QPainter);
- d->initFrom(device);
+ return d->engine != nullptr;
}
-#endif
void QPainterPrivate::initFrom(const QPaintDevice *device)
{
@@ -1603,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));
}
/*!
@@ -1628,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) {
@@ -1636,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;
}
@@ -1658,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;
@@ -1682,8 +1637,7 @@ void QPainter::restore()
tmp->changeFlags |= QPaintEngine::DirtyTransform;
}
- d->updateState(d->state);
- delete tmp;
+ d->updateState(d->state.get());
}
@@ -1716,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;
@@ -1760,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());
@@ -1769,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:
@@ -1813,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;
}
@@ -1870,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());
@@ -1924,23 +1879,13 @@ bool QPainter::end()
}
}
- if (d->states.size() > 1) {
- qWarning("QPainter::end: Painter ended with %d saved states",
- 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);
@@ -1957,7 +1902,7 @@ bool QPainter::end()
QPaintEngine *QPainter::paintEngine() const
{
Q_D(const QPainter);
- return d->engine;
+ return d->engine.get();
}
/*!
@@ -2533,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: {
@@ -2700,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)
@@ -2892,175 +2837,6 @@ void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
d->updateState(d->state);
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \since 4.2
- \obsolete
-
- Sets the transformation matrix to \a matrix and enables transformations.
-
- \note It is advisable to use setWorldTransform() instead of this function to
- preserve the properties of perspective transformations.
-
- If \a combine is true, then \a matrix is combined with the current
- transformation matrix; otherwise \a matrix replaces the current
- transformation matrix.
-
- If \a matrix is the identity matrix and \a combine is false, this
- function calls setWorldMatrixEnabled(false). (The identity matrix is the
- matrix where QMatrix::m11() and QMatrix::m22() are 1.0 and the
- rest are 0.0.)
-
- The following functions can transform the coordinate system without using
- a QMatrix:
- \list
- \li translate()
- \li scale()
- \li shear()
- \li rotate()
- \endlist
-
- They operate on the painter's worldMatrix() and are implemented like this:
-
- \snippet code/src_gui_painting_qpainter.cpp 4
-
- Note that when using setWorldMatrix() function you should always have
- \a combine be true when you are drawing into a QPicture. Otherwise
- it may not be possible to replay the picture with additional
- transformations; using the translate(), scale(), etc. convenience
- functions is safe.
-
- For more information about the coordinate system, transformations
- and window-viewport conversion, see \l {Coordinate System}.
-
- \sa setWorldTransform(), QTransform
-*/
-
-void QPainter::setWorldMatrix(const QMatrix &matrix, bool combine)
-{
- setWorldTransform(QTransform(matrix), combine);
-}
-
-/*!
- \since 4.2
- \obsolete
-
- Returns the world transformation matrix.
-
- It is advisable to use worldTransform() because worldMatrix() does not
- preserve the properties of perspective transformations.
-
- \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
- {Coordinate System}
-*/
-
-const QMatrix &QPainter::worldMatrix() const
-{
- Q_D(const QPainter);
- if (!d->engine) {
- qWarning("QPainter::worldMatrix: Painter not active");
- return d->fakeState()->transform.toAffine();
- }
- return d->state->worldMatrix.toAffine();
-}
-
-/*!
- \obsolete
-
- Use setWorldTransform() instead.
-
- \sa setWorldTransform()
-*/
-
-void QPainter::setMatrix(const QMatrix &matrix, bool combine)
-{
- setWorldTransform(QTransform(matrix), combine);
-}
-
-/*!
- \obsolete
-
- Use worldTransform() instead.
-
- \sa worldTransform()
-*/
-
-const QMatrix &QPainter::matrix() const
-{
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- return worldMatrix();
-QT_WARNING_POP
-}
-
-
-/*!
- \since 4.2
- \obsolete
-
- Returns the transformation matrix combining the current
- window/viewport and world transformation.
-
- It is advisable to use combinedTransform() instead of this
- function to preserve the properties of perspective transformations.
-
- \sa setWorldTransform(), setWindow(), setViewport()
-*/
-QMatrix QPainter::combinedMatrix() const
-{
- return combinedTransform().toAffine();
-}
-
-
-/*!
- \obsolete
-
- Returns the matrix that transforms from logical coordinates to
- device coordinates of the platform dependent paint device.
-
- \note It is advisable to use deviceTransform() instead of this
- function to preserve the properties of perspective transformations.
-
- This function is \e only needed when using platform painting
- commands on the platform dependent handle (Qt::HANDLE), and the
- platform does not do transformations nativly.
-
- The QPaintEngine::PaintEngineFeature enum can be queried to
- determine whether the platform performs the transformations or
- not.
-
- \sa worldMatrix(), QPaintEngine::hasFeature(),
-*/
-const QMatrix &QPainter::deviceMatrix() const
-{
- Q_D(const QPainter);
- if (!d->engine) {
- qWarning("QPainter::deviceMatrix: Painter not active");
- return d->fakeState()->transform.toAffine();
- }
- return d->state->matrix.toAffine();
-}
-
-/*!
- \obsolete
-
- Resets any transformations that were made using translate(), scale(),
- shear(), rotate(), setWorldMatrix(), setViewport() and
- setWindow().
-
- It is advisable to use resetTransform() instead of this function
- to preserve the properties of perspective transformations.
-
- \sa {QPainter#Coordinate Transformations}{Coordinate
- Transformations}
-*/
-
-void QPainter::resetMatrix()
-{
- resetTransform();
-}
-#endif
-
/*!
\since 4.2
@@ -3110,34 +2886,6 @@ bool QPainter::worldMatrixEnabled() const
return d->state->WxF;
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \obsolete
-
- Use setWorldMatrixEnabled() instead.
-
- \sa setWorldMatrixEnabled()
-*/
-
-void QPainter::setMatrixEnabled(bool enable)
-{
- setWorldMatrixEnabled(enable);
-}
-
-/*!
- \obsolete
-
- Use worldMatrixEnabled() instead
-
- \sa worldMatrixEnabled()
-*/
-
-bool QPainter::matrixEnabled() const
-{
- return worldMatrixEnabled();
-}
-#endif
-
/*!
Scales the coordinate system by (\a{sx}, \a{sy}).
@@ -3276,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) {
@@ -3289,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;
@@ -3320,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;
@@ -3363,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;
@@ -3630,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
@@ -3796,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.
*/
/*!
@@ -3804,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.
*/
/*!
@@ -4099,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) {
@@ -4159,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);
@@ -4195,54 +3940,6 @@ void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
Draws the given rectangle \a x, \a y, \a w, \a h with rounded corners.
*/
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \obsolete
-
- Draws a rectangle \a r with rounded corners.
-
- The \a xRnd and \a yRnd arguments specify how rounded the corners
- should be. 0 is angled corners, 99 is maximum roundedness.
-
- A filled rectangle has a size of r.size(). A stroked rectangle
- has a size of r.size() plus the pen width.
-
- \sa drawRoundedRect()
-*/
-void QPainter::drawRoundRect(const QRectF &r, int xRnd, int yRnd)
-{
- drawRoundedRect(r, xRnd, yRnd, Qt::RelativeSize);
-}
-
-
-/*!
- \fn void QPainter::drawRoundRect(const QRect &r, int xRnd = 25, int yRnd = 25)
-
- \overload
- \obsolete
-
- Draws the rectangle \a r with rounded corners.
-*/
-void QPainter::drawRoundRect(const QRect &rect, int xRnd, int yRnd)
-{
- drawRoundedRect(QRectF(rect), xRnd, yRnd, Qt::RelativeSize);
-}
-
-/*!
- \obsolete
-
- \fn QPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd)
-
- \overload
-
- Draws the rectangle \a x, \a y, \a w, \a h with rounded corners.
-*/
-void QPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd)
-{
- drawRoundedRect(QRectF(x, y, w, h), xRnd, yRnd, Qt::RelativeSize);
-}
-#endif
-
/*!
\fn void QPainter::drawEllipse(const QRectF &rectangle)
@@ -4269,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());
@@ -4310,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());
@@ -4397,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();
@@ -4459,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);
@@ -4528,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();
@@ -4687,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
@@ -4696,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
@@ -4704,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
@@ -4712,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
@@ -5608,40 +5315,31 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
}
- d->drawGlyphs(glyphIndexes, fixedPointPositions.data(), count, fontD->fontEngine,
- glyphRun.overline(), glyphRun.underline(), glyphRun.strikeOut());
+ d->drawGlyphs(engineRequiresPretransformedGlyphPositions
+ ? d->state->transform().map(position)
+ : position,
+ glyphIndexes,
+ fixedPointPositions.data(),
+ count,
+ fontD->fontEngine,
+ glyphRun.overline(),
+ glyphRun.underline(),
+ glyphRun.strikeOut());
}
-void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positions,
+void QPainterPrivate::drawGlyphs(const QPointF &decorationPosition,
+ const quint32 *glyphArray,
+ QFixedPoint *positions,
int glyphCount,
- QFontEngine *fontEngine, bool overline, bool underline,
+ QFontEngine *fontEngine,
+ bool overline,
+ bool underline,
bool strikeOut)
{
Q_Q(QPainter);
updateState(state);
- QFixed leftMost;
- QFixed rightMost;
- QFixed baseLine;
- for (int i=0; i<glyphCount; ++i) {
- glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
- if (i == 0 || leftMost > positions[i].x)
- leftMost = positions[i].x;
-
- // We don't support glyphs that do not share a common baseline. If this turns out to
- // be a relevant use case, then we need to find clusters of glyphs that share a baseline
- // and do a drawTextItemDecorations call per cluster.
- if (i == 0 || baseLine < positions[i].y)
- baseLine = positions[i].y;
-
- // We use the advance rather than the actual bounds to match the algorithm in drawText()
- if (i == 0 || rightMost < positions[i].x + gm.xoff)
- rightMost = positions[i].x + gm.xoff;
- }
-
- QFixed width = rightMost - leftMost;
-
if (extended != nullptr && state->matrix.isAffine()) {
QStaticTextItem staticTextItem;
staticTextItem.color = state->pen.color();
@@ -5675,21 +5373,15 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positio
engine->drawTextItem(QPointF(0, 0), textItem);
}
- QTextItemInt::RenderFlags flags;
- if (underline)
- flags |= QTextItemInt::Underline;
- if (overline)
- flags |= QTextItemInt::Overline;
- if (strikeOut)
- flags |= QTextItemInt::StrikeOut;
-
- drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()),
- fontEngine,
- nullptr, // textEngine
- (underline
- ? QTextCharFormat::SingleUnderline
- : QTextCharFormat::NoUnderline),
- flags, width.toReal(), QTextCharFormat());
+ qt_draw_decoration_for_glyphs(q,
+ decorationPosition,
+ glyphArray,
+ positions,
+ glyphCount,
+ fontEngine,
+ underline,
+ overline,
+ strikeOut);
}
#endif // QT_NO_RAWFONT
@@ -5769,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);
@@ -5869,9 +5565,15 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
}
d->extended->drawStaticTextItem(item);
- qt_draw_decoration_for_glyphs(this, item->glyphs, item->glyphPositions,
- item->numGlyphs, item->fontEngine(), staticText_d->font,
- QTextCharFormat());
+ qt_draw_decoration_for_glyphs(this,
+ topLeftPosition,
+ item->glyphs,
+ item->glyphPositions,
+ item->numGlyphs,
+ item->fontEngine(),
+ staticText_d->font.underline(),
+ staticText_d->font.overline(),
+ staticText_d->font.strikeOut());
}
if (currentColor != oldPen.color())
setPen(oldPen);
@@ -5895,22 +5597,6 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif
if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
return;
-#if QT_DEPRECATED_SINCE(5, 11) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- if (tf & Qt::TextBypassShaping) {
- // Skip complex shaping, shape using glyph advances only
- int len = str.length();
- int numGlyphs = len;
- QVarLengthGlyphLayoutArray glyphs(len);
- QFontEngine *fontEngine = d->state->font.d->engineForScript(QChar::Script_Common);
- if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, { }))
- Q_UNREACHABLE();
-
- QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine);
- drawTextItem(p, gf);
- return;
- }
-#endif
-
QStackTextEngine engine(str, d->state->font);
engine.option.setTextDirection(d->state->layoutDirection);
if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
@@ -5919,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();
@@ -5974,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)
@@ -6061,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)
@@ -6161,7 +5847,8 @@ void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *
\overload
Draws the given \a text in the \a rectangle specified using the \a option
- to control its positioning and orientation.
+ to control its positioning, direction, and orientation. The options given
+ in \a option override those set on the QPainter object itself.
By default, QPainter draws text anti-aliased.
@@ -6179,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)
@@ -6219,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.
*/
@@ -6227,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());
@@ -6294,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) {
@@ -6352,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);
@@ -6362,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);
@@ -6371,54 +6058,46 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
painter->setPen(oldPen);
painter->setBrush(oldBrush);
-
- if (wasCompatiblePainting)
- painter->setRenderHint(QPainter::Qt4CompatiblePainting);
}
-Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
- const QFixedPoint *positions, int glyphCount,
- QFontEngine *fontEngine, const QFont &font,
- const QTextCharFormat &charFormat)
+static void qt_draw_decoration_for_glyphs(QPainter *painter,
+ const QPointF &decorationPosition,
+ const glyph_t *glyphArray,
+ const QFixedPoint *positions,
+ int glyphCount,
+ QFontEngine *fontEngine,
+ bool underline,
+ bool overline,
+ bool strikeOut)
{
- if (!(font.underline() || font.strikeOut() || font.overline()))
+ if (!underline && !overline && !strikeOut)
return;
- QFixed leftMost;
- QFixed rightMost;
- QFixed baseLine;
- for (int i=0; i<glyphCount; ++i) {
- glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
- if (i == 0 || leftMost > positions[i].x)
- leftMost = positions[i].x;
-
- // We don't support glyphs that do not share a common baseline. If this turns out to
- // be a relevant use case, then we need to find clusters of glyphs that share a baseline
- // and do a drawTextItemDecoration call per cluster.
- if (i == 0 || baseLine < positions[i].y)
- baseLine = positions[i].y;
-
- // We use the advance rather than the actual bounds to match the algorithm in drawText()
- if (i == 0 || rightMost < positions[i].x + gm.xoff)
- rightMost = positions[i].x + gm.xoff;
- }
-
- QFixed width = rightMost - leftMost;
QTextItem::RenderFlags flags;
-
- if (font.underline())
+ if (underline)
flags |= QTextItem::Underline;
- if (font.overline())
+ if (overline)
flags |= QTextItem::Overline;
- if (font.strikeOut())
+ if (strikeOut)
flags |= QTextItem::StrikeOut;
- drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()),
+ bool rtl = positions[glyphCount - 1].x < positions[0].x;
+ QFixed baseline = positions[0].y;
+ glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[rtl ? 0 : glyphCount - 1]);
+
+ qreal width = rtl
+ ? (positions[0].x + gm.xoff - positions[glyphCount - 1].x).toReal()
+ : (positions[glyphCount - 1].x + gm.xoff - positions[0].x).toReal();
+
+ drawTextItemDecoration(painter,
+ QPointF(decorationPosition.x(), baseline.toReal()),
fontEngine,
nullptr, // textEngine
- font.underline() ? QTextCharFormat::SingleUnderline
- : QTextCharFormat::NoUnderline, flags,
- width.toReal(), charFormat);
+ underline ? QTextCharFormat::SingleUnderline
+ : QTextCharFormat::NoUnderline,
+ flags,
+ width,
+ QTextCharFormat());
}
void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti)
@@ -6678,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;
@@ -6826,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
@@ -6841,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);
@@ -6953,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();
@@ -6991,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();
@@ -7032,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);
@@ -7401,89 +7084,6 @@ void QPainter::setViewTransformEnabled(bool enable)
d->updateMatrix();
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \threadsafe
-
- \obsolete
-
- Please use QWidget::render() instead.
-
- Redirects all paint commands for the given paint \a device, to the
- \a replacement device. The optional point \a offset defines an
- offset within the source device.
-
- The redirection will not be effective until the begin() function
- has been called; make sure to call end() for the given \a
- device's painter (if any) before redirecting. Call
- restoreRedirected() to restore the previous redirection.
-
- \warning Making use of redirections in the QPainter API implies
- that QPainter::begin() and QPaintDevice destructors need to hold
- a mutex for a short period. This can impact performance. Use of
- QWidget::render is strongly encouraged.
-
- \sa redirected(), restoreRedirected()
-*/
-void QPainter::setRedirected(const QPaintDevice *device,
- QPaintDevice *replacement,
- const QPoint &offset)
-{
- Q_ASSERT(device != nullptr);
- Q_UNUSED(device)
- Q_UNUSED(replacement)
- Q_UNUSED(offset)
- qWarning("QPainter::setRedirected(): ignoring call to deprecated function, use QWidget::render() instead");
-}
-
-/*!
- \threadsafe
-
- \obsolete
-
- Using QWidget::render() obsoletes the use of this function.
-
- Restores the previous redirection for the given \a device after a
- call to setRedirected().
-
- \warning Making use of redirections in the QPainter API implies
- that QPainter::begin() and QPaintDevice destructors need to hold
- a mutex for a short period. This can impact performance. Use of
- QWidget::render is strongly encouraged.
-
- \sa redirected()
- */
-void QPainter::restoreRedirected(const QPaintDevice *device)
-{
- Q_UNUSED(device)
- qWarning("QPainter::restoreRedirected(): ignoring call to deprecated function, use QWidget::render() instead");
-}
-
-/*!
- \threadsafe
-
- \obsolete
-
- Using QWidget::render() obsoletes the use of this function.
-
- Returns the replacement for given \a device. The optional out
- parameter \a offset returns the offset within the replaced device.
-
- \warning Making use of redirections in the QPainter API implies
- that QPainter::begin() and QPaintDevice destructors need to hold
- a mutex for a short period. This can impact performance. Use of
- QWidget::render is strongly encouraged.
-
- \sa setRedirected(), restoreRedirected()
-*/
-QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset)
-{
- Q_UNUSED(device)
- Q_UNUSED(offset)
- return nullptr;
-}
-#endif
-
void qt_format_text(const QFont &fnt, const QRectF &_r,
int tf, const QString& str, QRectF *brect,
int tabstops, int *ta, int tabarraylen,
@@ -7555,28 +7155,28 @@ 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 == QChar(ushort(0x9c))) {
+ } else if (chr == u'\x9c') {
// string with multiple length variants
hasMoreLengthVariants = true;
break;
}
}
- QVector<QTextLayout::FormatRange> underlineFormats;
+ QList<QTextLayout::FormatRange> underlineFormats;
int length = offset - old_offset;
if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
QChar *cout = text.data() + old_offset;
@@ -7584,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;
@@ -7598,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;
@@ -7661,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();
@@ -8085,31 +7685,6 @@ QFont QPaintEngineState::font() const
return static_cast<const QPainterState *>(this)->font;
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \since 4.2
- \obsolete
-
- Returns the matrix in the current paint engine
- state.
-
- \note It is advisable to use transform() instead of this function to
- preserve the properties of perspective transformations.
-
- This variable should only be used when the state() returns a
- combination which includes the QPaintEngine::DirtyTransform flag.
-
- \sa state(), QPaintEngine::updateState()
-*/
-
-QMatrix QPaintEngineState::matrix() const
-{
- const QPainterState *st = static_cast<const QPainterState *>(this);
-
- return st->matrix.toAffine();
-}
-#endif
-
/*!
\since 4.3
@@ -8590,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 3394da63c7..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,12 +12,12 @@
#include <QtGui/qpixmap.h>
#include <QtGui/qimage.h>
#include <QtGui/qtextoption.h>
+#include <memory>
#ifndef QT_INCLUDE_COMPAT
#include <QtGui/qpolygon.h>
#include <QtGui/qpen.h>
#include <QtGui/qbrush.h>
-#include <QtGui/qmatrix.h>
#include <QtGui/qtransform.h>
#include <QtGui/qfontinfo.h>
#include <QtGui/qfontmetrics.h>
@@ -72,7 +36,6 @@ class QPen;
class QPolygon;
class QTextItem;
class QTextEngine;
-class QMatrix;
class QTransform;
class QStaticText;
class QGlyphRun;
@@ -89,14 +52,11 @@ public:
Antialiasing = 0x01,
TextAntialiasing = 0x02,
SmoothPixmapTransform = 0x04,
-#if QT_DEPRECATED_SINCE(5, 14)
- HighQualityAntialiasing Q_DECL_ENUMERATOR_DEPRECATED_X("Use Antialiasing instead") = 0x08,
- NonCosmeticDefaultPen Q_DECL_ENUMERATOR_DEPRECATED_X("Default pen is non-cosmetic now") = 0x10,
-#endif
- Qt4CompatiblePainting = 0x20,
+ VerticalSubpixelPositioning = 0x08,
LosslessImageRendering = 0x40,
+ NonCosmeticBrushPatterns = 0x80
};
- Q_FLAG(RenderHint)
+ Q_ENUM(RenderHint)
Q_DECLARE_FLAGS(RenderHints, RenderHint)
Q_FLAG(RenderHints)
@@ -134,11 +94,6 @@ public:
bool end();
bool isActive() const;
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use begin(QPaintDevice*) instead")
- void initFrom(const QPaintDevice *device);
-#endif
-
enum CompositionMode {
CompositionMode_SourceOver,
CompositionMode_DestinationOver,
@@ -237,35 +192,11 @@ public:
void restore();
// XForm functions
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use setTransform() instead")
- void setMatrix(const QMatrix &matrix, bool combine = false);
- QT_DEPRECATED_X("Use transform() instead")
- const QMatrix &matrix() const;
- QT_DEPRECATED_X("Use deviceTransform() instead")
- const QMatrix &deviceMatrix() const;
- QT_DEPRECATED_X("Use resetTransform() instead")
- void resetMatrix();
-#endif
-
void setTransform(const QTransform &transform, bool combine = false);
const QTransform &transform() const;
const QTransform &deviceTransform() const;
void resetTransform();
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use setWorldTransform() instead")
- void setWorldMatrix(const QMatrix &matrix, bool combine = false);
- QT_DEPRECATED_X("Use worldTransform() instead")
- const QMatrix &worldMatrix() const;
- QT_DEPRECATED_X("Use combinedTransform() instead")
- QMatrix combinedMatrix() const;
- QT_DEPRECATED_X("Use setWorldMatrixEnabled() instead")
- void setMatrixEnabled(bool enabled);
- QT_DEPRECATED_X("Use worldMatrixEnabled() instead")
- bool matrixEnabled() const;
-#endif
-
void setWorldTransform(const QTransform &matrix, bool combine = false);
const QTransform &worldTransform() const;
@@ -314,22 +245,22 @@ public:
inline void drawLine(const QPointF &p1, const QPointF &p2);
void drawLines(const QLineF *lines, int lineCount);
- inline void drawLines(const QVector<QLineF> &lines);
+ inline void drawLines(const QList<QLineF> &lines);
void drawLines(const QPointF *pointPairs, int lineCount);
- inline void drawLines(const QVector<QPointF> &pointPairs);
+ inline void drawLines(const QList<QPointF> &pointPairs);
void drawLines(const QLine *lines, int lineCount);
- inline void drawLines(const QVector<QLine> &lines);
+ inline void drawLines(const QList<QLine> &lines);
void drawLines(const QPoint *pointPairs, int lineCount);
- inline void drawLines(const QVector<QPoint> &pointPairs);
+ inline void drawLines(const QList<QPoint> &pointPairs);
inline void drawRect(const QRectF &rect);
inline void drawRect(int x1, int y1, int w, int h);
inline void drawRect(const QRect &rect);
void drawRects(const QRectF *rects, int rectCount);
- inline void drawRects(const QVector<QRectF> &rectangles);
+ inline void drawRects(const QList<QRectF> &rectangles);
void drawRects(const QRect *rects, int rectCount);
- inline void drawRects(const QVector<QRect> &rectangles);
+ inline void drawRects(const QList<QRect> &rectangles);
void drawEllipse(const QRectF &r);
void drawEllipse(const QRect &r);
@@ -372,15 +303,6 @@ public:
inline void drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius,
Qt::SizeMode mode = Qt::AbsoluteSize);
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use drawRoundedRect(..., Qt::RelativeSize) instead")
- void drawRoundRect(const QRectF &r, int xround = 25, int yround = 25);
- QT_DEPRECATED_X("Use drawRoundedRect(..., Qt::RelativeSize) instead")
- void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25);
- QT_DEPRECATED_X("Use drawRoundedRect(..., Qt::RelativeSize) instead")
- void drawRoundRect(const QRect &r, int xround = 25, int yround = 25);
-#endif
-
void drawTiledPixmap(const QRectF &rect, const QPixmap &pm, const QPointF &offset = QPointF());
inline void drawTiledPixmap(int x, int y, int w, int h, const QPixmap &, int sx=0, int sy=0);
inline void drawTiledPixmap(const QRect &, const QPixmap &, const QPoint & = QPoint());
@@ -482,27 +404,17 @@ 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;
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use QWidget::render() instead")
- static void setRedirected(const QPaintDevice *device, QPaintDevice *replacement,
- const QPoint& offset = QPoint());
- QT_DEPRECATED_X("Use QWidget::render() instead")
- static QPaintDevice *redirected(const QPaintDevice *device, QPoint *offset = nullptr);
- QT_DEPRECATED_X("Use QWidget::render() instead")
- static void restoreRedirected(const QPaintDevice *device);
-#endif
-
void beginNativePainting();
void endNativePainting();
private:
Q_DISABLE_COPY(QPainter)
- QScopedPointer<QPainterPrivate> d_ptr;
+ std::unique_ptr<QPainterPrivate> d_ptr;
friend class QWidget;
friend class QFontEngine;
@@ -554,54 +466,54 @@ inline void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
drawLine(QLineF(p1, p2));
}
-inline void QPainter::drawLines(const QVector<QLineF> &lines)
+inline void QPainter::drawLines(const QList<QLineF> &lines)
{
- drawLines(lines.constData(), lines.size());
+ drawLines(lines.constData(), int(lines.size()));
}
-inline void QPainter::drawLines(const QVector<QLine> &lines)
+inline void QPainter::drawLines(const QList<QLine> &lines)
{
- drawLines(lines.constData(), lines.size());
+ drawLines(lines.constData(), int(lines.size()));
}
-inline void QPainter::drawLines(const QVector<QPointF> &pointPairs)
+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 QVector<QPoint> &pointPairs)
+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)
@@ -620,14 +532,14 @@ inline void QPainter::drawRect(const QRect &r)
drawRects(&r, 1);
}
-inline void QPainter::drawRects(const QVector<QRectF> &rects)
+inline void QPainter::drawRects(const QList<QRectF> &rects)
{
- drawRects(rects.constData(), rects.size());
+ drawRects(rects.constData(), int(rects.size()));
}
-inline void QPainter::drawRects(const QVector<QRect> &rects)
+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)
@@ -648,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 285bd90502..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
@@ -59,13 +23,15 @@
#include "QtGui/qfont.h"
#include "QtGui/qpen.h"
#include "QtGui/qregion.h"
-#include "QtGui/qmatrix.h"
#include "QtGui/qpainter.h"
#include "QtGui/qpainterpath.h"
#include "QtGui/qpaintengine.h"
#include <private/qpen_p.h>
+#include <memory>
+#include <stack>
+
QT_BEGIN_NAMESPACE
class QPaintEngine;
@@ -101,7 +67,7 @@ inline bool qbrush_has_transform(const QBrush &b) { return data_ptr(b)->transfor
class QPainterClipInfo
{
public:
- QPainterClipInfo() {} // for QVector, don't use
+ QPainterClipInfo() { } // for QList, don't use
enum ClipType { RegionClip, PathClip, RectClip, RectFClip };
QPainterClipInfo(const QPainterPath &p, Qt::ClipOperation op, const QTransform &m) :
@@ -139,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
{
@@ -159,7 +125,7 @@ public:
QPainterPath clipPath;
Qt::ClipOperation clipOperation = Qt::NoClip;
QPainter::RenderHints renderHints;
- QVector<QPainterClipInfo> clipInfo; // ### Make me smaller and faster to copy around...
+ QList<QPainterClipInfo> clipInfo; // ### Make me smaller and faster to copy around...
QTransform worldMatrix; // World transformation matrix, not window and viewport
QTransform matrix; // Complete transformation matrix,
QTransform redirectionMatrix;
@@ -192,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 QPainterDummyState *dummyState;
+ 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,
@@ -222,13 +189,14 @@ public:
QPainterDummyState *fakeState() const {
if (!dummyState)
- dummyState = new QPainterDummyState();
- return dummyState;
+ dummyState = std::make_unique<QPainterDummyState>();
+ return dummyState.get();
}
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);
@@ -236,7 +204,7 @@ public:
void drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine);
#if !defined(QT_NO_RAWFONT)
- void drawGlyphs(const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
+ void drawGlyphs(const QPointF &decorationPosition, const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
QFontEngine *fontEngine, bool overline = false, bool underline = false,
bool strikeOut = false);
#endif
@@ -248,7 +216,7 @@ public:
static QPainterPrivate *get(QPainter *painter)
{
- return painter->d_ptr.data();
+ return painter->d_ptr.get();
}
QTransform viewTransform() const;
@@ -258,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
};
@@ -271,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 17d8b863ab..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"
@@ -44,7 +8,6 @@
#include <qdebug.h>
#include <qiodevice.h>
#include <qlist.h>
-#include <qmatrix.h>
#include <qpen.h>
#include <qpolygon.h>
#include <qtextlayout.h>
@@ -89,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.
@@ -557,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
@@ -570,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;
@@ -614,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;
}
@@ -669,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)
@@ -754,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;
@@ -804,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()))
@@ -863,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());
@@ -1202,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
@@ -1210,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)
{
@@ -1222,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();
@@ -1248,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
@@ -1289,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);
@@ -1320,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);
@@ -1367,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;
}
/*!
@@ -1510,7 +1449,7 @@ QRectF QPainterPath::boundingRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyBounds)
computeBoundingRect();
@@ -1531,7 +1470,7 @@ QRectF QPainterPath::controlPointRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyControlBounds)
computeControlPointRect();
@@ -1550,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);
}
/*!
@@ -1661,14 +1600,6 @@ QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
}
/*!
- \overload
- */
-QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
-{
- return toSubpathPolygons(QTransform(matrix));
-}
-
-/*!
Converts the path into a list of polygons using the
QTransform \a matrix, and returns the list.
@@ -1701,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();
@@ -1712,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
@@ -1740,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)) {
@@ -1769,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) {
@@ -1787,14 +1718,6 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
return polys;
}
-/*!
- \overload
- */
-QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
-{
- return toFillPolygons(QTransform(matrix));
-}
-
//same as qt_polygon_isect_line in qpolygon.cpp
static void qt_painterpath_isect_line(const QPointF &p1,
const QPointF &p2,
@@ -1874,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;
@@ -2168,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))
@@ -2333,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) {
@@ -2519,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;
@@ -2549,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;
}
@@ -2609,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
@@ -2828,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)
@@ -2847,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;
}
@@ -2888,7 +2809,6 @@ void QPainterPathStroker::setDashOffset(qreal offset)
*/
QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
{
-
const QList<QPolygonF> flats = toSubpathPolygons(matrix);
QPolygonF polygon;
if (flats.isEmpty())
@@ -2904,15 +2824,6 @@ QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
return polygon;
}
-/*!
- \overload
-*/
-QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
-{
- return toFillPolygon(QTransform(matrix));
-}
-
-
//derivative of the equation
static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
{
@@ -3260,131 +3171,6 @@ void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadi
Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
*/
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \obsolete
-
- Adds a rectangle \a r with rounded corners to the path.
-
- The \a xRnd and \a yRnd arguments specify how rounded the corners
- should be. 0 is angled corners, 99 is maximum roundedness.
-
- \sa addRoundedRect()
-*/
-void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
-{
- if(xRnd >= 100) // fix ranges
- xRnd = 99;
- if(yRnd >= 100)
- yRnd = 99;
- if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
- addRect(r);
- return;
- }
-
- QRectF rect = r.normalized();
-
- if (rect.isNull())
- return;
-
- qreal x = rect.x();
- qreal y = rect.y();
- qreal w = rect.width();
- qreal h = rect.height();
- qreal rxx2 = w*xRnd/100;
- qreal ryy2 = h*yRnd/100;
-
- ensureData();
- detach();
-
- bool first = d_func()->elements.size() < 2;
-
- arcMoveTo(x, y, rxx2, ryy2, 180);
- arcTo(x, y, rxx2, ryy2, 180, -90);
- arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
- arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
- arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
- closeSubpath();
-
- d_func()->require_moveTo = true;
- d_func()->convex = first;
-}
-
-/*!
- \obsolete
-
- \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
- \since 4.3
- \overload
-
- Adds a rounded rectangle, \a rect, to the path.
-
- The \a roundness argument specifies uniform roundness for the
- rectangle. Vertical and horizontal roundness factors will be
- adjusted accordingly to act uniformly around both axes. Use this
- method if you want a rectangle equally rounded across both the X and
- Y axis.
-
- \sa addRoundedRect()
-*/
-void QPainterPath::addRoundRect(const QRectF &rect,
- int roundness)
-{
- int xRnd = roundness;
- int yRnd = roundness;
- if (rect.width() > rect.height())
- xRnd = int(roundness * rect.height()/rect.width());
- else
- yRnd = int(roundness * rect.width()/rect.height());
- addRoundedRect(rect, xRnd, yRnd, Qt::RelativeSize);
-}
-
-/*!
- \obsolete
-
- \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
- \overload
-
- Adds a rectangle with rounded corners to the path. The rectangle
- is constructed from \a x, \a y, and the width and height \a w
- and \a h.
-
- The \a xRnd and \a yRnd arguments specify how rounded the corners
- should be. 0 is angled corners, 99 is maximum roundedness.
-
- \sa addRoundedRect()
- */
-void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h,
- int xRnd, int yRnd)
-{
- addRoundedRect(QRectF(x, y, w, h), xRnd, yRnd, Qt::RelativeSize);
-}
-
-/*!
- \obsolete
-
- \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
- \since 4.3
- \overload
-
- Adds a rounded rectangle to the path, defined by the coordinates \a
- x and \a y with the specified \a width and \a height.
-
- The \a roundness argument specifies uniform roundness for the
- rectangle. Vertical and horizontal roundness factors will be
- adjusted accordingly to act uniformly around both axes. Use this
- method if you want a rectangle equally rounded across both the X and
- Y axis.
-
- \sa addRoundedRect()
-*/
-void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h,
- int roundness)
-{
- addRoundedRect(QRectF(x, y, w, h), roundness, Qt::RelativeSize);
-}
-#endif
-
/*!
\since 4.3
@@ -3438,21 +3224,6 @@ QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
return clipper.clip(QPathClipper::BoolSub);
}
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \since 4.3
- \obsolete
-
- Use subtracted() instead.
-
- \sa subtracted()
-*/
-QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
-{
- return p.subtracted(*this);
-}
-#endif
-
/*!
\since 4.4
@@ -3464,7 +3235,7 @@ QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
*/
QPainterPath QPainterPath::simplified() const
{
- if(isEmpty())
+ if (isEmpty())
return *this;
QPathClipper clipper(*this, QPainterPath());
return clipper.clip(QPathClipper::Simplify);
@@ -3523,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();
@@ -3570,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 ed5be667b7..4caf1aa5c0 100644
--- a/src/gui/painting/qpainterpath.h
+++ b/src/gui/painting/qpainterpath.h
@@ -1,52 +1,16 @@
-/****************************************************************************
-**
-** 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
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qmatrix.h>
+#include <QtGui/qtransform.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qrect.h>
#include <QtCore/qline.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
@@ -54,11 +18,11 @@ QT_BEGIN_NAMESPACE
class QFont;
class QPainterPathPrivate;
struct QPainterPathPrivateDeleter;
-class QPainterPathData;
class QPainterPathStrokerPrivate;
class QPen;
class QPolygonF;
class QRegion;
+class QTransform;
class QVectorPath;
class Q_GUI_EXPORT QPainterPath
@@ -92,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); }
@@ -141,19 +104,6 @@ public:
qreal xRadius, qreal yRadius,
Qt::SizeMode mode = Qt::AbsoluteSize);
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use addRoundedRect(..., Qt::RelativeSize) instead")
- void addRoundRect(const QRectF &rect, int xRnd, int yRnd);
- QT_DEPRECATED_X("Use addRoundedRect(..., Qt::RelativeSize) instead")
- void addRoundRect(qreal x, qreal y, qreal w, qreal h,
- int xRnd, int yRnd);
- QT_DEPRECATED_X("Use addRoundedRect(..., Qt::RelativeSize) instead")
- void addRoundRect(const QRectF &rect, int roundness);
- QT_DEPRECATED_X("Use addRoundedRect(..., Qt::RelativeSize) instead")
- void addRoundRect(qreal x, qreal y, qreal w, qreal h,
- int roundness);
-#endif
-
void connectPath(const QPainterPath &path);
bool contains(const QPointF &pt) const;
@@ -163,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;
@@ -174,13 +124,11 @@ public:
bool isEmpty() const;
- Q_REQUIRED_RESULT QPainterPath toReversed() const;
- QList<QPolygonF> toSubpathPolygons(const QMatrix &matrix = QMatrix()) const;
- QList<QPolygonF> toFillPolygons(const QMatrix &matrix = QMatrix()) const;
- QPolygonF toFillPolygon(const QMatrix &matrix = QMatrix()) const;
- QList<QPolygonF> toSubpathPolygons(const QTransform &matrix) const;
- QList<QPolygonF> toFillPolygons(const QTransform &matrix) const;
- QPolygonF toFillPolygon(const QTransform &matrix) const;
+ [[nodiscard]] QPainterPath toReversed() const;
+
+ QList<QPolygonF> toSubpathPolygons(const QTransform &matrix = QTransform()) const;
+ QList<QPolygonF> toFillPolygons(const QTransform &matrix = QTransform()) const;
+ QPolygonF toFillPolygon(const QTransform &matrix = QTransform()) const;
int elementCount() const;
QPainterPath::Element elementAt(int i) const;
@@ -194,15 +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;
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use r.subtracted() instead")
- Q_REQUIRED_RESULT QPainterPath subtractedInverted(const QPainterPath &r) const;
-#endif
+ [[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;
@@ -217,22 +161,19 @@ 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 QMatrix;
friend class QTransform;
friend class QVectorPath;
friend Q_GUI_EXPORT const QVectorPath &qtVectorPathForPath(const QPainterPath &);
@@ -243,7 +184,7 @@ private:
#endif
};
-Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QPainterPath)
+Q_DECLARE_SHARED(QPainterPath)
Q_DECLARE_TYPEINFO(QPainterPath::Element, Q_PRIMITIVE_TYPE);
#ifndef QT_NO_DATASTREAM
@@ -275,8 +216,8 @@ public:
qreal curveThreshold() const;
void setDashPattern(Qt::PenStyle);
- void setDashPattern(const QVector<qreal> &dashPattern);
- QVector<qreal> dashPattern() const;
+ void setDashPattern(const QList<qreal> &dashPattern);
+ QList<qreal> dashPattern() const;
void setDashOffset(qreal offset);
qreal dashOffset() const;
@@ -356,6 +297,8 @@ inline void QPainterPath::translate(const QPointF &offset)
inline QPainterPath QPainterPath::translated(const QPointF &offset) const
{ return translated(offset.x(), offset.y()); }
+inline QPainterPath operator *(const QPainterPath &p, const QTransform &m)
+{ return m.map(p); }
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QPainterPath &);
diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h
index a420e0b3d9..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,72 +31,25 @@
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 QMatrix;
- 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;
- QVector<QPainterPath::Element> elements;
-};
-
-class QPainterPathStrokerPrivate
-{
-public:
- QPainterPathStrokerPrivate();
-
- QStroker stroker;
- QVector<qfixed> dashPattern;
- qreal dashOffset;
-};
-
class QPolygonF;
class QVectorPathConverter;
class QVectorPathConverter
{
public:
- QVectorPathConverter(const QVector<QPainterPath::Element> &path, uint fillRule, bool convex)
+ QVectorPathConverter(const QList<QPainterPath::Element> &path, uint fillRule, bool convex)
: pathData(path, fillRule, convex),
- path(pathData.points.data(), path.size(),
- pathData.elements.data(), pathData.flags) {}
+ path(pathData.points.data(), path.size(), pathData.elements.data(), pathData.flags)
+ {
+ }
const QVectorPath &vectorPath() {
return path;
}
struct QVectorPathData {
- QVectorPathData(const QVector<QPainterPath::Element> &path, uint fillRule, bool convex)
- : elements(path.size()),
- points(path.size() * 2),
- flags(0)
+ QVectorPathData(const QList<QPainterPath::Element> &path, uint fillRule, bool convex)
+ : elements(path.size()), points(path.size() * 2), flags(0)
{
int ptsPos = 0;
bool isLines = true;
@@ -175,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)
{
}
- 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(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 &operator=(const QPainterPathData &) = delete;
- ~QPainterPathData() = default;
+ 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)
+ {
+ }
+
+ QPainterPathPrivate &operator=(const QPainterPathPrivate &) = delete;
+ ~QPainterPathPrivate() = default;
inline bool isClosed() const;
inline void close();
@@ -217,6 +163,9 @@ public:
return pathConverter->path;
}
+private:
+ QList<QPainterPath::Element> elements;
+
int cStart;
Qt::FillRule fillRule;
@@ -231,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++];
@@ -272,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;
@@ -296,7 +254,7 @@ inline void QPainterPathData::close()
}
}
-inline void QPainterPathData::maybeMoveTo()
+inline void QPainterPathPrivate::maybeMoveTo()
{
if (require_moveTo) {
QPainterPath::Element e = elements.last();
@@ -306,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 1a1b2d76e2..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;
};
@@ -316,7 +281,7 @@ static inline qreal coordinate(const QPointF &pos, int axis)
TreeNode SegmentTree::buildTree(int first, int last, int depth, const RectF &bounds)
{
if (depth >= 24 || (last - first) <= 10) {
- TreeNode node;
+ TreeNode node = {};
node.leaf = true;
node.index.interval.first = first;
node.index.interval.last = last;
@@ -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 9444a87b71..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
{
@@ -282,7 +252,7 @@ private:
QDataBuffer<QPathEdge> m_edges;
QDataBuffer<QPathVertex> m_vertices;
- QVector<qreal> m_splitPoints;
+ QList<qreal> m_splitPoints;
QPathSegments m_segments;
};
@@ -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 932c3e6f5a..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";
@@ -1390,6 +1340,18 @@ void QPdfEngine::setPdfVersion(PdfVersion version)
d->pdfVersion = version;
}
+void QPdfEngine::setDocumentXmpMetadata(const QByteArray &xmpMetadata)
+{
+ Q_D(QPdfEngine);
+ d->xmpDocumentMetadata = xmpMetadata;
+}
+
+QByteArray QPdfEngine::documentXmpMetadata() const
+{
+ Q_D(const QPdfEngine);
+ return d->xmpDocumentMetadata;
+}
+
void QPdfEngine::setPageLayout(const QPageLayout &pageLayout)
{
Q_D(QPdfEngine);
@@ -1468,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();
@@ -1520,11 +1482,17 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
d->xrefPositions.clear();
d->pageRoot = 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();
@@ -1555,10 +1523,19 @@ bool QPdfEngine::end()
d->outDevice = nullptr;
}
+ d->destCache.clear();
+ d->fileCache.clear();
+
setActive(false);
return true;
}
+void QPdfEngine::addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType)
+{
+ Q_D(QPdfEngine);
+ d->fileCache.push_back({fileName, data, mimeType});
+}
+
QPdfEnginePrivate::~QPdfEnginePrivate()
{
qDeleteAll(fonts);
@@ -1586,13 +1563,16 @@ void QPdfEnginePrivate::writeHeader()
int metaDataObj = -1;
int outputIntentObj = -1;
+ if (pdfVersion == QPdfEngine::Version_A1b || !xmpDocumentMetadata.isEmpty()) {
+ metaDataObj = writeXmpDcumentMetaData();
+ }
if (pdfVersion == QPdfEngine::Version_A1b) {
- metaDataObj = writeXmpMetaData();
outputIntentObj = writeOutputIntent();
}
catalog = addXrefEntry(-1);
pageRoot = requestObject();
+ namesRoot = requestObject();
// catalog
{
@@ -1600,12 +1580,14 @@ void QPdfEnginePrivate::writeHeader()
QPdf::ByteStream s(&catalog);
s << "<<\n"
<< "/Type /Catalog\n"
- << "/Pages " << pageRoot << "0 R\n";
+ << "/Pages " << pageRoot << "0 R\n"
+ << "/Names " << namesRoot << "0 R\n";
- if (pdfVersion == QPdfEngine::Version_A1b) {
- s << "/OutputIntents [" << outputIntentObj << "0 R]\n";
+ if (pdfVersion == QPdfEngine::Version_A1b || !xmpDocumentMetadata.isEmpty())
s << "/Metadata " << metaDataObj << "0 R\n";
- }
+
+ if (pdfVersion == QPdfEngine::Version_A1b)
+ s << "/OutputIntents [" << outputIntentObj << "0 R]\n";
s << ">>\n"
<< "endobj\n";
@@ -1626,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()
@@ -1664,39 +1744,46 @@ void QPdfEnginePrivate::writeInfo()
"endobj\n");
}
-int QPdfEnginePrivate::writeXmpMetaData()
+int QPdfEnginePrivate::writeXmpDcumentMetaData()
{
const int metaDataObj = addXrefEntry(-1);
+ QByteArray metaDataContent;
+
+ if (xmpDocumentMetadata.isEmpty()) {
+ const QString producer(QString::fromLatin1("Qt " QT_VERSION_STR));
+
+ const QDateTime now = QDateTime::currentDateTime();
+ const QDate date = now.date();
+ const QTime time = now.time();
+ const QString timeStr =
+ QString::asprintf("%d-%02d-%02dT%02d:%02d:%02d",
+ date.year(), date.month(), date.day(),
+ time.hour(), time.minute(), time.second());
+
+ const int offset = now.offsetFromUtc();
+ const int hours = (offset / 60) / 60;
+ const int mins = (offset / 60) % 60;
+ QString tzStr;
+ if (offset < 0)
+ tzStr = QString::asprintf("-%02d:%02d", -hours, -mins);
+ else if (offset > 0)
+ tzStr = QString::asprintf("+%02d:%02d", hours , mins);
+ else
+ tzStr = "Z"_L1;
- const QString producer(QString::fromLatin1("Qt " QT_VERSION_STR));
-
- const QDateTime now = QDateTime::currentDateTime();
- const QDate date = now.date();
- const QTime time = now.time();
- const QString timeStr =
- QString::asprintf("%d-%02d-%02dT%02d:%02d:%02d",
- date.year(), date.month(), date.day(),
- time.hour(), time.minute(), time.second());
+ const QString metaDataDate = timeStr + tzStr;
- const int offset = now.offsetFromUtc();
- const int hours = (offset / 60) / 60;
- const int mins = (offset / 60) % 60;
- QString tzStr;
- if (offset < 0)
- tzStr = QString::asprintf("-%02d:%02d", -hours, -mins);
- else if (offset > 0)
- tzStr = QString::asprintf("+%02d:%02d", hours , mins);
+ 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(),
+ metaDataDate).toUtf8();
+ }
else
- tzStr = QLatin1String("Z");
-
- const QString metaDataDate = timeStr + tzStr;
+ metaDataContent = xmpDocumentMetadata;
- QFile metaDataFile(QLatin1String(":/qpdf/qpdfa_metadata.xml"));
- metaDataFile.open(QIODevice::ReadOnly);
- const QByteArray metaDataContent = QString::fromUtf8(metaDataFile.readAll()).arg(producer.toHtmlEscaped(),
- title.toHtmlEscaped(),
- creator.toHtmlEscaped(),
- metaDataDate).toUtf8();
xprintf("<<\n"
"/Type /Metadata /Subtype /XML\n"
"/Length %d\n"
@@ -1713,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;
@@ -1774,6 +1862,103 @@ 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;
+
+ QList<int> attachments;
+ const int size = fileCache.size();
+ for (int i = 0; i < size; ++i) {
+ auto attachment = fileCache.at(i);
+ const int attachmentID = addXrefEntry(-1);
+ xprintf("<<\n");
+ if (do_compress)
+ xprintf("/Filter /FlateDecode\n");
+
+ const int lenobj = requestObject();
+ xprintf("/Length %d 0 R\n", lenobj);
+ int len = 0;
+ xprintf(">>\nstream\n");
+ len = writeCompressed(attachment.data);
+ xprintf("\nendstream\n"
+ "endobj\n");
+ addXrefEntry(lenobj);
+ xprintf("%d\n"
+ "endobj\n", len);
+
+ attachments.push_back(addXrefEntry(-1));
+ xprintf("<<\n"
+ "/F (%s)", attachment.fileName.toLatin1().constData());
+
+ xprintf("\n/EF <</F %d 0 R>>\n"
+ "/Type/Filespec\n"
+ , attachmentID);
+ if (!attachment.mimeType.isEmpty())
+ xprintf("/Subtype/%s\n",
+ attachment.mimeType.replace("/"_L1, "#2F"_L1).toLatin1().constData());
+ xprintf(">>\nendobj\n");
+ }
+
+ // names
+ attachmentsRoot = addXrefEntry(-1);
+ xprintf("<</Names[");
+ for (int i = 0; i < size; ++i) {
+ auto attachment = fileCache.at(i);
+ printString(attachment.fileName);
+ xprintf("%d 0 R\n", attachments.at(i));
+ }
+ xprintf("]>>\n"
+ "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)
{
@@ -1868,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");
@@ -1891,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++;
@@ -1972,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));
@@ -2031,6 +2222,10 @@ void QPdfEnginePrivate::writeTail()
writePage();
writeFonts();
writePageRoot();
+ writeDestsRoot();
+ writeAttachmentRoot();
+ writeNamesRoot();
+
addXrefEntry(xrefPositions.size(),false);
xprintf("xref\n"
"0 %d\n"
@@ -2078,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("()");
@@ -2089,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] == '\\')
@@ -2207,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
{
@@ -2227,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);
@@ -2237,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");
@@ -2245,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 %s\n", (depth == 32) ? "/DeviceRGB" : "/DeviceGray");
+ "/ColorSpace /DeviceGray\n");
+ break;
+ case WriteImageOption::RGB:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceRGB\n");
+ break;
+ case WriteImageOption::CMYK:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceCMYK\n");
+ break;
}
+
if (maskObject > 0)
xprintf("/Mask %d 0 R\n", maskObject);
if (softMaskObject > 0)
@@ -2263,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");
@@ -2287,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()) {
@@ -2299,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) {
@@ -2314,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";
@@ -2323,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) {
@@ -2383,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)
@@ -2429,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);
@@ -2497,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);
@@ -2594,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
@@ -2617,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;
@@ -2645,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));
@@ -2706,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
@@ -2719,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()
@@ -2736,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()) {
@@ -2764,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;
}
@@ -2772,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;
@@ -2783,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;
@@ -2795,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) {
@@ -2813,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
@@ -2863,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);
@@ -2876,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.;
@@ -2896,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) }));
}
}
@@ -2941,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;
@@ -3003,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;
@@ -3023,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 89e549614a..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
@@ -55,13 +19,12 @@
#ifndef QT_NO_PDF
-#include "QtGui/qmatrix.h"
+#include "QtCore/qlist.h"
#include "QtCore/qstring.h"
-#include "QtCore/qvector.h"
-#include "private/qstroker_p.h"
-#include "private/qpaintengine_p.h"
#include "private/qfontengine_p.h"
#include "private/qfontsubset_p.h"
+#include "private/qpaintengine_p.h"
+#include "private/qstroker_p.h"
#include "qpagelayout.h"
QT_BEGIN_NAMESPACE
@@ -87,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();
@@ -95,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();
@@ -148,13 +109,13 @@ class QPdfPage : public QPdf::ByteStream
public:
QPdfPage();
- QVector<uint> images;
- QVector<uint> graphicStates;
- QVector<uint> patterns;
- QVector<uint> fonts;
- QVector<uint> annotations;
+ QList<uint> images;
+ QList<uint> graphicStates;
+ QList<uint> patterns;
+ 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:
@@ -177,7 +138,7 @@ public:
};
QPdfEngine();
- QPdfEngine(QPdfEnginePrivate &d);
+ explicit QPdfEngine(QPdfEnginePrivate &d);
~QPdfEngine() {}
void setOutputFilename(const QString &filename);
@@ -187,6 +148,23 @@ public:
void setPdfVersion(PdfVersion version);
+ void setDocumentXmpMetadata(const QByteArray &xmpMetadata);
+ QByteArray documentXmpMetadata() const;
+
+ 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;
@@ -261,14 +239,16 @@ public:
QPointF brushOrigin;
QBrush brush;
QPen pen;
- QVector<QPainterPath> clips;
+ QList<QPainterPath> clips;
bool clipEnabled;
bool allClipped;
bool hasPen;
bool hasBrush;
bool simplePen;
+ bool needsTransform;
qreal opacity;
QPdfEngine::PdfVersion pdfVersion;
+ QPdfEngine::ColorModel colorModel;
QHash<QFontEngine::FaceId, QFontSubset *> fonts;
@@ -284,7 +264,6 @@ public:
QString creator;
bool embedFonts;
int resolution;
- bool grayscale;
// Page layout: size, orientation and margins
QPageLayout m_pageLayout;
@@ -294,26 +273,51 @@ 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 writeXmpMetaData();
+ int writeXmpDcumentMetaData();
int writeOutputIntent();
void writePageRoot();
+ void writeDestsRoot();
+ void writeAttachmentRoot();
+ void writeNamesRoot();
void writeFonts();
void embedFont(QFontSubset *font);
qreal calcUserUnit() const;
- QVector<int> xrefPositions;
+ QList<int> xrefPositions;
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());
@@ -321,14 +325,37 @@ 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
+ {
+ AttachmentInfo (const QString &fileName, const QByteArray &data, const QString &mimeType)
+ : fileName(fileName), data(data), mimeType(mimeType) {}
+ QString fileName;
+ QByteArray data;
+ QString mimeType;
+ };
+
+ struct DestInfo
+ {
+ QString anchor;
+ uint pageObj;
+ QPointF coords;
+ };
+
// various PDF objects
- int pageRoot, catalog, info, graphicsState, patternColorSpace;
- QVector<uint> pages;
+ 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;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index 35814d146c..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>
@@ -266,143 +230,49 @@ int QPdfWriter::resolution() const
return d->engine->resolution();
}
-// 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.
-
- \sa pageLayout()
-*/
-
-/*!
- \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().
+ \since 5.15
- Returns true if the page margins were successfully set to \a margins.
+ Sets the document metadata. This metadata is not influenced by the setTitle / setCreator methods,
+ so is up to the user to keep it consistent.
+ \a xmpMetadata contains XML formatted metadata to embed into the PDF file.
- \sa pageLayout()
+ \sa documentXmpMetadata()
*/
-/*!
- \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
+void QPdfWriter::setDocumentXmpMetadata(const QByteArray &xmpMetadata)
+{
+ Q_D(const QPdfWriter);
+ d->engine->setDocumentXmpMetadata(xmpMetadata);
+}
-#if QT_DEPRECATED_SINCE(5, 14)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
/*!
- \reimp
+ \since 5.15
- \obsolete Use setPageSize(QPageSize(id)) instead
+ Gets the document metadata, as it was provided with a call to setDocumentXmpMetadata. It will not
+ return the default metadata.
- \sa setPageSize()
+ \sa setDocumentXmpMetadata()
*/
-void QPdfWriter::setPageSize(PageSize size)
+QByteArray QPdfWriter::documentXmpMetadata() const
{
- setPageSize(QPageSize(QPageSize::PageSizeId(size)));
+ Q_D(const QPdfWriter);
+ return d->engine->documentXmpMetadata();
}
/*!
- \reimp
-
- \obsolete Use setPageSize(QPageSize(size, QPageSize::Millimeter)) instead
+ \since 5.15
- \sa setPageSize()
+ Adds \a fileName attachment to the PDF with (optional) \a mimeType.
+ \a data contains the raw file data to embed into the PDF file.
*/
-void QPdfWriter::setPageSizeMM(const QSizeF &size)
+void QPdfWriter::addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType)
{
- setPageSize(QPageSize(size, QPageSize::Millimeter));
+ Q_D(QPdfWriter);
+ d->engine->addFileAttachment(fileName, data, mimeType);
}
-QT_WARNING_POP
-#endif
/*!
\internal
@@ -425,24 +295,55 @@ bool QPdfWriter::newPage()
return d->engine->newPage();
}
+/*!
+ \enum QPdfWriter::ColorModel
+ \since 6.8
+
+ 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).
+
+ \value RGB All colors are converted to RGB and saved as such in the
+ PDF.
+
+ \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.
+
+ \value CMYK All colors are converted to CMYK and saved as such.
+
+ \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 QColor, QGradient
+*/
-#if QT_DEPRECATED_SINCE(5, 14)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
/*!
- \reimp
+ \since 6.8
- \obsolete Use setPageMargins(QMarginsF(l, t, r, b), QPageLayout::Millimeter) instead
+ Returns the color model used by this PDF writer.
+ The default is QPdfWriter::ColorModel::Auto.
+*/
+QPdfWriter::ColorModel QPdfWriter::colorModel() const
+{
+ Q_D(const QPdfWriter);
+ return static_cast<ColorModel>(d->engine->d_func()->colorModel);
+}
- \sa setPageMargins()
- */
-void QPdfWriter::setMargins(const Margins &m)
+/*!
+ \since 6.8
+
+ Sets the color model used by this PDF writer to \a model.
+*/
+void QPdfWriter::setColorModel(ColorModel model)
{
- setPageMargins(QMarginsF(m.left, m.top, m.right, m.bottom), QPageLayout::Millimeter);
+ Q_D(QPdfWriter);
+ 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 668081e008..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
@@ -75,25 +39,22 @@ public:
void setResolution(int resolution);
int resolution() const;
-#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
+ void setDocumentXmpMetadata(const QByteArray &xmpMetadata);
+ QByteArray documentXmpMetadata() const;
-#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
+ void addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType = QString());
+
+ 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 1a940443d1..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(QVariant::Pen, 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 10b11d1d85..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,17 +37,15 @@ 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);
- QVector<qreal> dashPattern() const;
- void setDashPattern(const QVector<qreal> &pattern);
+ QList<qreal> dashPattern() const;
+ void setDashPattern(const QList<qreal> &pattern);
qreal dashOffset() const;
void setDashOffset(qreal doffset);
@@ -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
new file mode 100644
index 0000000000..4f2f0ae13a
--- /dev/null
+++ b/src/gui/painting/qpixellayout.cpp
@@ -0,0 +1,2436 @@
+// 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>
+
+#include "qdrawhelper_p.h"
+#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> 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<> 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<> 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<> 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<> 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<> 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<> 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<> 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<> 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<> 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<> 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<> 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; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
+
+template <QPixelLayout::BPP width> static
+void QT_FASTCALL storePixel(uchar *dest, int index, uint pixel);
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
+{
+ reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
+{
+ 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 inline uint convertPixelToRGB32(uint s)
+{
+ constexpr uint redMask = ((1 << redWidth<Format>()) - 1);
+ constexpr uint greenMask = ((1 << greenWidth<Format>()) - 1);
+ constexpr uint blueMask = ((1 << blueWidth<Format>()) - 1);
+
+ constexpr uchar redLeftShift = 8 - redWidth<Format>();
+ constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
+ constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
+
+ 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;
+ uint blue = (s >> blueShift<Format>()) & blueMask;
+
+ red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
+ green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
+ blue = (blue << blueLeftShift) | (blue >> blueRightShift);
+ return 0xff000000 | red | green | blue;
+}
+
+template<QImage::Format Format>
+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]);
+}
+
+#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
+extern const uint * QT_FASTCALL fetchPixelsBPP24_ssse3(uint *dest, const uchar*src, int index, int count);
+#endif
+
+template<QImage::Format Format>
+static const uint *QT_FASTCALL fetchRGBToRGB32(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
+#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
+ if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
+ // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
+ // to vectorize the deforested version below.
+ fetchPixelsBPP24_ssse3(buffer, src, index, count);
+ convertToRGB32<Format>(buffer, count, nullptr);
+ return buffer;
+ }
+#endif
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGB32<Format>(fetchPixel<BPP>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+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 QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGB64<Format>(src[i]);
+ return buffer;
+}
+
+template<QImage::Format Format>
+static const QRgba64 *QT_FASTCALL fetchRGBToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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] = convertPixelToRGB32F<Format>(fetchPixel<bitsPerPixel<Format>()>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+static inline uint convertPixelToARGB32PM(uint s)
+{
+ 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);
+
+ constexpr uchar alphaLeftShift = 8 - alphaWidth<Format>();
+ constexpr uchar redLeftShift = 8 - redWidth<Format>();
+ constexpr uchar greenLeftShift = 8 - greenWidth<Format>();
+ constexpr uchar blueLeftShift = 8 - blueWidth<Format>();
+
+ 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;
+
+ constexpr bool mustMin = (alphaWidth<Format>() != redWidth<Format>()) ||
+ (alphaWidth<Format>() != greenWidth<Format>()) ||
+ (alphaWidth<Format>() != blueWidth<Format>());
+
+ uint alpha = (s >> alphaShift<Format>()) & alphaMask;
+ uint red = (s >> redShift<Format>()) & redMask;
+ uint green = (s >> greenShift<Format>()) & greenMask;
+ uint blue = (s >> blueShift<Format>()) & blueMask;
+
+ alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
+ red = (red << redLeftShift) | (red >> redRightShift);
+ green = (green << greenLeftShift) | (green >> greenRightShift);
+ blue = (blue << blueLeftShift) | (blue >> blueRightShift);
+
+ if (mustMin) {
+ red = qMin(alpha, red);
+ green = qMin(alpha, green);
+ blue = qMin(alpha, blue);
+ }
+
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+}
+
+template<QImage::Format Format>
+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]);
+}
+
+template<QImage::Format Format>
+static const uint *QT_FASTCALL fetchARGBPMToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
+#if defined(__SSE2__) && !defined(__SSSE3__) && QT_COMPILER_SUPPORTS_SSSE3
+ if (BPP == QPixelLayout::BPP24 && qCpuHasFeature(SSSE3)) {
+ // With SSE2 can convertToRGB32 be vectorized, but it takes SSSE3
+ // to vectorize the deforested version below.
+ fetchPixelsBPP24_ssse3(buffer, src, index, count);
+ convertARGBPMToARGB32PM<Format>(buffer, count, nullptr);
+ return buffer;
+ }
+#endif
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToARGB32PM<Format>(fetchPixel<BPP>(src, index + i));
+ return buffer;
+}
+
+template<QImage::Format Format>
+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 QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = convertPixelToRGB64<Format>(src[i]);
+ return buffer;
+}
+
+template<QImage::Format Format>
+static const QRgba64 *QT_FASTCALL fetchARGBPMToRGBA64PM(QRgba64 *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] = 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 QList<QRgb> *, QDitherInfo *dither)
+{
+ 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)) {
+ 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]);
+ const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
+ const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
+ const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
+ storePixel<BPP>(dest, index + i, r | g | b);
+ };
+ } else {
+ // We do ordered dither by using a rounding conversion, but instead of
+ // adding half of input precision, we add the adjusted result from the
+ // bayer matrix before narrowing.
+ // Note: Rounding conversion in itself is different from the naive
+ // conversion we do above for non-dithering.
+ const uint *bayer_line = qt_bayer_matrix[dither->y & 15];
+ for (int i = 0; i < count; ++i) {
+ const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]);
+ const int d = bayer_line[(dither->x + i) & 15];
+ const int dr = d - ((d + 1) >> rWidth);
+ const int dg = d - ((d + 1) >> gWidth);
+ const int db = d - ((d + 1) >> bWidth);
+ int r = qRed(c);
+ int g = qGreen(c);
+ int b = qBlue(c);
+ r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
+ g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
+ b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
+ const uint s = (r << redShift<Format>())
+ | (g << greenShift<Format>())
+ | (b << blueShift<Format>());
+ storePixel<BPP>(dest, index + i, s);
+ }
+ }
+}
+
+template<QImage::Format Format, bool fromRGB>
+static void QT_FASTCALL storeARGBPMFromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *dither)
+{
+ constexpr QPixelLayout::BPP BPP = bitsPerPixel<Format>();
+ if (!dither) {
+ 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;
+
+ constexpr uchar aRightShift = 32 - alphaWidth<Format>();
+ constexpr uchar rRightShift = 24 - redWidth<Format>();
+ constexpr uchar gRightShift = 16 - greenWidth<Format>();
+ constexpr uchar bRightShift = 8 - blueWidth<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>());
+ const uint r = ((c >> rRightShift) & rMask) << redShift<Format>();
+ const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>();
+ const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>();
+ storePixel<BPP>(dest, index + i, a | r | g | b);
+ };
+ } else {
+ 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) {
+ const uint c = src[i];
+ const int d = bayer_line[(dither->x + i) & 15];
+ const int da = d - ((d + 1) >> aWidth);
+ const int dr = d - ((d + 1) >> rWidth);
+ const int dg = d - ((d + 1) >> gWidth);
+ const int db = d - ((d + 1) >> bWidth);
+ int a = qAlpha(c);
+ int r = qRed(c);
+ int g = qGreen(c);
+ int b = qBlue(c);
+ if (fromRGB)
+ a = (1 << aWidth) - 1;
+ else
+ a = (a + ((da - a) >> aWidth) + 1) >> (8 - aWidth);
+ r = (r + ((dr - r) >> rWidth) + 1) >> (8 - rWidth);
+ g = (g + ((dg - g) >> gWidth) + 1) >> (8 - gWidth);
+ b = (b + ((db - b) >> bWidth) + 1) >> (8 - bWidth);
+ uint s = (a << alphaShift<Format>())
+ | (r << redShift<Format>())
+ | (g << greenShift<Format>())
+ | (b << blueShift<Format>());
+ storePixel<BPP>(dest, index + i, s);
+ }
+ }
+}
+
+template<QImage::Format Format>
+static void QT_FASTCALL rbSwap(uchar *dst, const uchar *src, int count)
+{
+ 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);
+ 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 = fetchPixel<bpp>(src, i);
+ const uint r = (c >> rShift) & redBlueMask;
+ const uint b = (c >> bShift) & redBlueMask;
+ const uint t = (c & alphaGreenMask)
+ | (r << bShift)
+ | (b << rShift);
+ storePixel<bpp>(dst, i, t);
+ }
+}
+
+static void QT_FASTCALL rbSwap_rgb32(uchar *d, const uchar *s, int count)
+{
+ const uint *src = reinterpret_cast<const uint *>(s);
+ uint *dest = reinterpret_cast<uint *>(d);
+ for (int i = 0; i < count; ++i) {
+ const uint c = src[i];
+ const uint ag = c & 0xff00ff00;
+ const uint rb = c & 0x00ff00ff;
+ dest[i] = ag | (rb << 16) | (rb >> 16);
+ }
+}
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+template<>
+void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
+{
+ return rbSwap_rgb32(d, s, count);
+}
+#else
+template<>
+void QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uchar *d, const uchar *s, int count)
+{
+ const uint *src = reinterpret_cast<const uint *>(s);
+ uint *dest = reinterpret_cast<uint *>(d);
+ for (int i = 0; i < count; ++i) {
+ const uint c = src[i];
+ const uint rb = c & 0xff00ff00;
+ const uint ga = c & 0x00ff00ff;
+ dest[i] = ga | (rb << 16) | (rb >> 16);
+ }
+}
+#endif
+
+static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
+{
+ const uint *src = reinterpret_cast<const uint *>(s);
+ uint *dest = reinterpret_cast<uint *>(d);
+ UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
+}
+
+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,
+ false,
+ bitsPerPixel<Format>(),
+ rbSwap<Format>,
+ convertToRGB32<Format>,
+ convertToRGB64<Format>,
+ fetchRGBToRGB32<Format>,
+ fetchRGBToRGB64<Format>,
+ storeRGBFromARGB32PM<Format, false>,
+ storeRGBFromARGB32PM<Format, true>
+ };
+}
+
+template<QImage::Format Format> constexpr static inline QPixelLayout pixelLayoutARGBPM()
+{
+ return QPixelLayout{
+ true,
+ true,
+ bitsPerPixel<Format>(),
+ rbSwap<Format>,
+ convertARGBPMToARGB32PM<Format>,
+ convertARGBPMToRGBA64PM<Format>,
+ fetchARGBPMToARGB32PM<Format>,
+ fetchARGBPMToRGBA64PM<Format>,
+ storeARGBPMFromARGB32PM<Format, false>,
+ storeARGBPMFromARGB32PM<Format, true>
+ };
+}
+
+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]));
+}
+
+template<QPixelLayout::BPP BPP>
+static const uint *QT_FASTCALL fetchIndexedToARGB32PM(uint *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] = qPremultiply(clut->at(s));
+ }
+ return buffer;
+}
+
+template<QPixelLayout::BPP BPP>
+static const QRgba64 *QT_FASTCALL fetchIndexedToRGBA64PM(QRgba64 *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] = QRgba64::fromArgb32(clut->at(s)).premultiplied();
+ }
+ return buffer;
+}
+
+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] = QRgba::fromArgb32(clut->at(src[i])).premultiplied();
+ return buffer;
+}
+
+static void QT_FASTCALL convertPassThrough(uint *, int, const QList<QRgb> *)
+{
+}
+
+static const uint *QT_FASTCALL fetchPassThrough(uint *, const uchar *src, int index, int,
+ 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 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 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 QList<QRgb> *)
+{
+ qt_convertARGB32ToARGB32PM(buffer, buffer, count);
+}
+
+static const uint *QT_FASTCALL fetchARGB32ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ 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 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 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 QList<QRgb> *)
+{
+ qt_convertRGBA8888ToARGB32PM(buffer, buffer, count);
+}
+
+static const uint *QT_FASTCALL fetchRGBA8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ 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 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 QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qRgba(0, 0, 0, src[index + i]);
+ return buffer;
+}
+
+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] = QRgba::fromRgba(0, 0, 0, src[i]);
+ return buffer;
+}
+
+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] = QRgba::fromRgba(0, 0, 0, src[index + i]);
+ return buffer;
+}
+
+static void QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, int count, const QList<QRgb> *)
+{
+ for (int i = 0; i < count; ++i) {
+ const uint s = buffer[i];
+ buffer[i] = qRgb(s, s, s);
+ }
+}
+
+static const uint *QT_FASTCALL fetchGrayscale8ToRGB32(uint *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] = qRgb(s, s, s);
+ }
+ return buffer;
+}
+
+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] = QRgba::fromRgba(src[i], src[i], src[i], 255);
+ return buffer;
+}
+
+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] = QRgba::fromRgba(s, s, s, 255);
+ }
+ return buffer;
+}
+
+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 QList<QRgb> *, QDitherInfo *)
+{
+ const unsigned short *s = reinterpret_cast<const unsigned short *>(src) + index;
+ for (int i = 0; i < count; ++i) {
+ const uint x = qt_div_257(s[i]);
+ buffer[i] = qRgb(x, x, x);
+ }
+ return buffer;
+}
+
+template<typename QRgba>
+static const QRgba *QT_FASTCALL convertGrayscale16To(QRgba *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba::fromRgba64(src[i], src[i], src[i], 65535);
+ return buffer;
+}
+
+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] = 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 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 QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ UNALIASED_CONVERSION_LOOP(d, src, count, ARGB2RGBA);
+}
+
+#ifdef __SSE2__
+template<bool RGBA, bool maskAlpha>
+static inline void qConvertARGB32PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
+{
+ if (count <= 0)
+ return;
+
+ const __m128i amask = _mm_set1_epi32(0xff000000);
+ int i = 0;
+ for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) {
+ uint s = *src++;
+ if (maskAlpha)
+ s = s | 0xff000000;
+ if (RGBA)
+ s = RGBA2ARGB(s);
+ *buffer++ = QRgba64::fromArgb32(s);
+ }
+ for (; i < count-3; i += 4) {
+ __m128i vs = _mm_loadu_si128((const __m128i*)src);
+ if (maskAlpha)
+ vs = _mm_or_si128(vs, amask);
+ src += 4;
+ __m128i v1 = _mm_unpacklo_epi8(vs, vs);
+ __m128i v2 = _mm_unpackhi_epi8(vs, vs);
+ if (!RGBA) {
+ v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
+ v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
+ v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2));
+ v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2));
+ }
+ _mm_store_si128((__m128i*)(buffer), v1);
+ buffer += 2;
+ _mm_store_si128((__m128i*)(buffer), v2);
+ buffer += 2;
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ uint s = *src++;
+ if (maskAlpha)
+ s = s | 0xff000000;
+ if (RGBA)
+ s = RGBA2ARGB(s);
+ *buffer++ = QRgba64::fromArgb32(s);
+ }
+}
+
+template<QtPixelOrder PixelOrder>
+static inline void qConvertRGBA64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count)
+{
+ const __m128i gmask = _mm_set1_epi32(0x000ffc00);
+ const __m128i cmask = _mm_set1_epi32(0x000003ff);
+ int i = 0;
+ __m128i vr, vg, vb, va;
+ for (; i < count && uintptr_t(buffer) & 0xF; ++i) {
+ *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
+ }
+
+ for (; i < count-15; i += 16) {
+ // Repremultiplying is really expensive and hard to do in SIMD without AVX2,
+ // so we try to avoid it by checking if it is needed 16 samples at a time.
+ __m128i vOr = _mm_set1_epi32(0);
+ __m128i vAnd = _mm_set1_epi32(0xffffffff);
+ for (int j = 0; j < 16; j += 2) {
+ __m128i vs = _mm_load_si128((const __m128i*)(buffer + j));
+ vOr = _mm_or_si128(vOr, vs);
+ vAnd = _mm_and_si128(vAnd, vs);
+ }
+ const quint16 orAlpha = ((uint)_mm_extract_epi16(vOr, 3)) | ((uint)_mm_extract_epi16(vOr, 7));
+ const quint16 andAlpha = ((uint)_mm_extract_epi16(vAnd, 3)) & ((uint)_mm_extract_epi16(vAnd, 7));
+
+ if (andAlpha == 0xffff) {
+ for (int j = 0; j < 16; j += 2) {
+ __m128i vs = _mm_load_si128((const __m128i*)buffer);
+ buffer += 2;
+ vr = _mm_srli_epi64(vs, 6);
+ vg = _mm_srli_epi64(vs, 16 + 6 - 10);
+ vb = _mm_srli_epi64(vs, 32 + 6);
+ vr = _mm_and_si128(vr, cmask);
+ vg = _mm_and_si128(vg, gmask);
+ vb = _mm_and_si128(vb, cmask);
+ va = _mm_srli_epi64(vs, 48 + 14);
+ if (PixelOrder == PixelOrderRGB)
+ vr = _mm_slli_epi32(vr, 20);
+ else
+ vb = _mm_slli_epi32(vb, 20);
+ va = _mm_slli_epi32(va, 30);
+ __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va));
+ vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0));
+ _mm_storel_epi64((__m128i*)dest, vd);
+ dest += 2;
+ }
+ } else if (orAlpha == 0) {
+ for (int j = 0; j < 16; ++j) {
+ *dest++ = 0;
+ buffer++;
+ }
+ } else {
+ for (int j = 0; j < 16; ++j)
+ *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
+ }
+ }
+
+ SIMD_EPILOGUE(i, count, 15)
+ *dest++ = qConvertRgb64ToRgb30<PixelOrder>(*buffer++);
+}
+#elif defined(__ARM_NEON__)
+template<bool RGBA, bool maskAlpha>
+static inline void qConvertARGB32PMToRGBA64PM_neon(QRgba64 *buffer, const uint *src, int count)
+{
+ if (count <= 0)
+ return;
+
+ const uint32x4_t amask = vdupq_n_u32(0xff000000);
+#if defined(Q_PROCESSOR_ARM_64)
+ const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
+#else
+ const uint8x8_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7 };
+#endif
+ int i = 0;
+ for (; i < count-3; i += 4) {
+ uint32x4_t vs32 = vld1q_u32(src);
+ src += 4;
+ if (maskAlpha)
+ vs32 = vorrq_u32(vs32, amask);
+ uint8x16_t vs8 = vreinterpretq_u8_u32(vs32);
+ if (!RGBA) {
+#if defined(Q_PROCESSOR_ARM_64)
+ vs8 = vqtbl1q_u8(vs8, rgbaMask);
+#else
+ // no vqtbl1q_u8
+ const uint8x8_t vlo = vtbl1_u8(vget_low_u8(vs8), rgbaMask);
+ const uint8x8_t vhi = vtbl1_u8(vget_high_u8(vs8), rgbaMask);
+ vs8 = vcombine_u8(vlo, vhi);
+#endif
+ }
+ uint8x16x2_t v = vzipq_u8(vs8, vs8);
+
+ vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[0]));
+ buffer += 2;
+ vst1q_u16((uint16_t *)buffer, vreinterpretq_u16_u8(v.val[1]));
+ buffer += 2;
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ uint s = *src++;
+ if (maskAlpha)
+ s = s | 0xff000000;
+ if (RGBA)
+ s = RGBA2ARGB(s);
+ *buffer++ = QRgba64::fromArgb32(s);
+ }
+}
+#endif
+
+static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+#ifdef __SSE2__
+ qConvertARGB32PMToRGBA64PM_sse2<false, true>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<false, true>(buffer, src, count);
+#else
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]);
+#endif
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGB32ToRGB64(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchARGB32ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 QList<QRgb> *, QDitherInfo *)
+{
+#ifdef __SSE2__
+ qConvertARGB32PMToRGBA64PM_sse2<false, false>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<false, false>(buffer, src, count);
+#else
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba64::fromArgb32(src[i]);
+#endif
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchARGB32PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 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 QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 QList<QRgb> *, QDitherInfo *)
+{
+#ifdef __SSE2__
+ qConvertARGB32PMToRGBA64PM_sse2<true, false>(buffer, src, count);
+#elif defined(__ARM_NEON__)
+ qConvertARGB32PMToRGBA64PM_neon<true, false>(buffer, src, count);
+#else
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i]));
+#endif
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchRGBA8888PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 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 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 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 QList<QRgb> *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(buffer[i]);
+}
+
+template<QtPixelOrder PixelOrder>
+static const uint *QT_FASTCALL fetchA2RGB30PMToARGB32PM(uint *buffer, const uchar *s, int index, int count,
+ const QList<QRgb> *, QDitherInfo *dither)
+{
+ const uint *src = reinterpret_cast<const uint *>(s) + index;
+ if (!dither) {
+ UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>);
+ } else {
+ for (int i = 0; i < count; ++i) {
+ const uint c = src[i];
+ short d10 = (qt_bayer_matrix[dither->y & 15][(dither->x + i) & 15] << 2);
+ short a10 = (c >> 30) * 0x155;
+ short r10 = ((c >> 20) & 0x3ff);
+ short g10 = ((c >> 10) & 0x3ff);
+ short b10 = (c & 0x3ff);
+ if (PixelOrder == PixelOrderBGR)
+ std::swap(r10, b10);
+ short a8 = (a10 + ((d10 - a10) >> 8)) >> 2;
+ short r8 = (r10 + ((d10 - r10) >> 8)) >> 2;
+ short g8 = (g10 + ((d10 - g10) >> 8)) >> 2;
+ short b8 = (b10 + ((d10 - b10) >> 8)) >> 2;
+ buffer[i] = qRgba(r8, g8, b8, a8);
+ }
+ }
+ return buffer;
+}
+
+#ifdef __SSE2__
+template<QtPixelOrder PixelOrder>
+static inline void qConvertA2RGB30PMToRGBA64PM_sse2(QRgba64 *buffer, const uint *src, int count)
+{
+ if (count <= 0)
+ return;
+
+ const __m128i rmask = _mm_set1_epi32(0x3ff00000);
+ const __m128i gmask = _mm_set1_epi32(0x000ffc00);
+ const __m128i bmask = _mm_set1_epi32(0x000003ff);
+ const __m128i afactor = _mm_set1_epi16(0x5555);
+ int i = 0;
+
+ for (; ((uintptr_t)buffer & 0xf) && i < count; ++i)
+ *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
+
+ for (; i < count-3; i += 4) {
+ __m128i vs = _mm_loadu_si128((const __m128i*)src);
+ src += 4;
+ __m128i va = _mm_srli_epi32(vs, 30);
+ __m128i vr = _mm_and_si128(vs, rmask);
+ __m128i vb = _mm_and_si128(vs, bmask);
+ __m128i vg = _mm_and_si128(vs, gmask);
+ va = _mm_mullo_epi16(va, afactor);
+ vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24));
+ vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14));
+ vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4));
+ __m128i vrb;
+ if (PixelOrder == PixelOrderRGB)
+ vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2));
+ else
+ vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2));
+ __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2));
+ _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga));
+ buffer += 2;
+ _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga));
+ buffer += 2;
+ }
+
+ SIMD_EPILOGUE(i, count, 3)
+ *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++);
+}
+#endif
+
+template<QtPixelOrder PixelOrder>
+static const QRgba64 *QT_FASTCALL convertA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+#ifdef __SSE2__
+ qConvertA2RGB30PMToRGBA64PM_sse2<PixelOrder>(buffer, src, count);
+#else
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertA2rgb30ToRgb64<PixelOrder>(src[i]);
+#endif
+ return buffer;
+}
+
+template<QtPixelOrder PixelOrder>
+static const QRgba64 *QT_FASTCALL fetchA2RGB30PMToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ 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 QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ UNALIASED_CONVERSION_LOOP(d, src, count, qConvertArgb32ToA2rgb30<PixelOrder>);
+}
+
+template<QtPixelOrder PixelOrder>
+static void QT_FASTCALL storeRGB30FromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
+}
+
+template<QtPixelOrder PixelOrder>
+static void QT_FASTCALL storeRGB30FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ UNALIASED_CONVERSION_LOOP(d, src, count, qConvertRgb32ToRgb30<PixelOrder>);
+}
+
+template<bool RGBA>
+void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count)
+{
+ int i = 0;
+#ifdef __SSE2__
+ if (((uintptr_t)dst & 0x7) && count > 0) {
+ uint s = (*src++).toArgb32();
+ if (RGBA)
+ s = ARGB2RGBA(s);
+ *dst++ = s;
+ i++;
+ }
+ const __m128i vhalf = _mm_set1_epi32(0x80);
+ const __m128i vzero = _mm_setzero_si128();
+ for (; i < count-1; i += 2) {
+ __m128i vs = _mm_loadu_si128((const __m128i*)src);
+ src += 2;
+ if (!RGBA) {
+ vs = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
+ vs = _mm_shufflehi_epi16(vs, _MM_SHUFFLE(3, 0, 1, 2));
+ }
+ __m128i v1 = _mm_unpacklo_epi16(vs, vzero);
+ __m128i v2 = _mm_unpackhi_epi16(vs, vzero);
+ v1 = _mm_add_epi32(v1, vhalf);
+ v2 = _mm_add_epi32(v2, vhalf);
+ v1 = _mm_sub_epi32(v1, _mm_srli_epi32(v1, 8));
+ v2 = _mm_sub_epi32(v2, _mm_srli_epi32(v2, 8));
+ v1 = _mm_srli_epi32(v1, 8);
+ v2 = _mm_srli_epi32(v2, 8);
+ v1 = _mm_packs_epi32(v1, v2);
+ v1 = _mm_packus_epi16(v1, vzero);
+ _mm_storel_epi64((__m128i*)(dst), v1);
+ dst += 2;
+ }
+#endif
+ for (; i < count; i++) {
+ uint s = (*src++).toArgb32();
+ if (RGBA)
+ s = ARGB2RGBA(s);
+ *dst++ = s;
+ }
+}
+template void qt_convertRGBA64ToARGB32<false>(uint *dst, const QRgba64 *src, int count);
+template void qt_convertRGBA64ToARGB32<true>(uint *dst, const QRgba64 *src, int count);
+
+
+static void QT_FASTCALL storeAlpha8FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ 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 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 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 QList<QRgb> *, QDitherInfo *)
+{
+ unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qGray(src[i]) * 257;
+}
+
+static void QT_FASTCALL storeGrayscale16FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ unsigned short *d = reinterpret_cast<unsigned short *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = qGray(qUnpremultiply(src[i])) * 257;
+}
+
+static const uint *QT_FASTCALL fetchRGB64ToRGB32(uint *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] = toArgb32(s[i]);
+ return buffer;
+}
+
+static void QT_FASTCALL storeRGB64FromRGB32(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] | 0xff000000);
+}
+
+static const uint *QT_FASTCALL fetchRGBA64ToARGB32PM(uint *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] = toArgb32(s[i].premultiplied());
+ return buffer;
+}
+
+template<bool Mask>
+static void QT_FASTCALL storeRGBA64FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64 *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ 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[] = {
+ { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
+ { false, false, QPixelLayout::BPP1MSB, nullptr,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
+ fetchIndexedToARGB32PM<QPixelLayout::BPP1MSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1MSB>,
+ nullptr, nullptr }, // Format_Mono
+ { false, false, QPixelLayout::BPP1LSB, nullptr,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
+ fetchIndexedToARGB32PM<QPixelLayout::BPP1LSB>, fetchIndexedToRGBA64PM<QPixelLayout::BPP1LSB>,
+ nullptr, nullptr }, // Format_MonoLSB
+ { false, false, QPixelLayout::BPP8, nullptr,
+ convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
+ fetchIndexedToARGB32PM<QPixelLayout::BPP8>, fetchIndexedToRGBA64PM<QPixelLayout::BPP8>,
+ nullptr, nullptr }, // Format_Indexed8
+ // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
+ // but everywhere this generic conversion would be wrong is currently overloaded.
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
+ convertRGB32ToRGB64, fetchPassThrough, fetchRGB32ToRGB64, storePassThrough, storePassThrough }, // Format_RGB32
+ { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM,
+ convertARGB32ToRGBA64PM, fetchARGB32ToARGB32PM, fetchARGB32ToRGBA64PM, storeARGB32FromARGB32PM, storePassThrough }, // Format_ARGB32
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough,
+ convertARGB32PMToRGBA64PM, fetchPassThrough, fetchARGB32PMToRGBA64PM, storePassThrough, storePassThrough }, // Format_ARGB32_Premultiplied
+ pixelLayoutRGB<QImage::Format_RGB16>(),
+ pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
+ pixelLayoutRGB<QImage::Format_RGB666>(),
+ pixelLayoutARGBPM<QImage::Format_ARGB6666_Premultiplied>(),
+ pixelLayoutRGB<QImage::Format_RGB555>(),
+ pixelLayoutARGBPM<QImage::Format_ARGB8555_Premultiplied>(),
+ pixelLayoutRGB<QImage::Format_RGB888>(),
+ pixelLayoutRGB<QImage::Format_RGB444>(),
+ pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
+ { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
+ convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBXFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBX8888
+ { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM,
+ convertRGBA8888ToRGBA64PM, fetchRGBA8888ToARGB32PM, fetchRGBA8888ToRGBA64PM, storeRGBA8888FromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888
+ { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM,
+ convertRGBA8888PMToRGBA64PM, fetchRGBA8888PMToARGB32PM, fetchRGBA8888PMToRGBA64PM, storeRGBA8888PMFromARGB32PM, storeRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
+ convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
+ convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
+ fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
+ fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
+ storeRGB30FromARGB32PM<PixelOrderBGR>,
+ storeRGB30FromRGB32<PixelOrderBGR>
+ }, // Format_BGR30
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
+ convertA2RGB30PMToARGB32PM<PixelOrderBGR>,
+ convertA2RGB30PMToRGBA64PM<PixelOrderBGR>,
+ fetchA2RGB30PMToARGB32PM<PixelOrderBGR>,
+ fetchA2RGB30PMToRGBA64PM<PixelOrderBGR>,
+ storeA2RGB30PMFromARGB32PM<PixelOrderBGR>,
+ storeRGB30FromRGB32<PixelOrderBGR>
+ }, // Format_A2BGR30_Premultiplied
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb30,
+ convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
+ convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
+ fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
+ fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
+ storeRGB30FromARGB32PM<PixelOrderRGB>,
+ storeRGB30FromRGB32<PixelOrderRGB>
+ }, // Format_RGB30
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb30,
+ convertA2RGB30PMToARGB32PM<PixelOrderRGB>,
+ convertA2RGB30PMToRGBA64PM<PixelOrderRGB>,
+ fetchA2RGB30PMToARGB32PM<PixelOrderRGB>,
+ fetchA2RGB30PMToRGBA64PM<PixelOrderRGB>,
+ storeA2RGB30PMFromARGB32PM<PixelOrderRGB>,
+ storeRGB30FromRGB32<PixelOrderRGB>
+ }, // Format_A2RGB30_Premultiplied
+ { true, true, QPixelLayout::BPP8, nullptr,
+ convertAlpha8ToRGB32, convertAlpha8To<QRgba64>,
+ fetchAlpha8ToRGB32, fetchAlpha8To<QRgba64>,
+ storeAlpha8FromARGB32PM, nullptr }, // Format_Alpha8
+ { false, false, QPixelLayout::BPP8, nullptr,
+ convertGrayscale8ToRGB32, convertGrayscale8To<QRgba64>,
+ fetchGrayscale8ToRGB32, fetchGrayscale8To<QRgba64>,
+ storeGrayscale8FromARGB32PM, storeGrayscale8FromRGB32 }, // Format_Grayscale8
+ { false, false, QPixelLayout::BPP64, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB64ToRGB32, fetchPassThrough64,
+ storeRGBA64FromARGB32PM<true>, storeRGB64FromRGB32 }, // Format_RGBX64
+ { true, false, QPixelLayout::BPP64, rbSwap_4x16,
+ convertARGB32ToARGB32PM, nullptr,
+ fetchRGBA64ToARGB32PM, fetchRGBA64ToRGBA64PM,
+ storeRGBA64FromARGB32PM<false>, storeRGB64FromRGB32 }, // Format_RGBA64
+ { true, true, QPixelLayout::BPP64, rbSwap_4x16,
+ convertPassThrough, nullptr,
+ fetchRGB64ToRGB32, fetchPassThrough64,
+ storeRGBA64FromARGB32, storeRGB64FromRGB32 }, // Format_RGBA64_Premultiplied
+ { false, false, QPixelLayout::BPP16, nullptr,
+ 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(std::size(qPixelLayouts) == QImage::NImageFormats);
+
+static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
+{
+ for (int i = 0; i < length; ++i) {
+ dest[i] = toArgb32(src[i]);
+ }
+}
+
+template<QImage::Format format>
+static void QT_FASTCALL storeGenericFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *clut, QDitherInfo *dither)
+{
+ uint buffer[BufferSize];
+ convertFromRgb64(buffer, src, count);
+ qPixelLayouts[format].storeFromARGB32PM(dest, buffer, index, count, clut, dither);
+}
+
+static void QT_FASTCALL storeARGB32FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = toArgb32(src[i].unpremultiplied());
+}
+
+static void QT_FASTCALL storeRGBA8888FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = toRgba8888(src[i].unpremultiplied());
+}
+
+template<QtPixelOrder PixelOrder>
+static void QT_FASTCALL storeRGB30FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = (uint*)dest + index;
+#ifdef __SSE2__
+ qConvertRGBA64PMToA2RGB30PM_sse2<PixelOrder>(d, src, count);
+#else
+ for (int i = 0; i < count; ++i)
+ d[i] = qConvertRgb64ToRgb30<PixelOrder>(src[i]);
+#endif
+}
+
+static void QT_FASTCALL storeRGBX64FromRGBA64PM(uchar *dest, const QRgba64 *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] = src[i].unpremultiplied();
+ d[i].setAlpha(65535);
+ }
+}
+
+static void QT_FASTCALL storeRGBA64FromRGBA64PM(uchar *dest, const QRgba64 *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] = src[i].unpremultiplied();
+}
+
+static void QT_FASTCALL storeRGBA64PMFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ QRgba64 *d = reinterpret_cast<QRgba64*>(dest) + index;
+ if (d != src)
+ memcpy(d, src, count * sizeof(QRgba64));
+}
+
+static void QT_FASTCALL storeGray16FromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ quint16 *d = reinterpret_cast<quint16*>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ QRgba64 s = src[i].unpremultiplied();
+ d[i] = qGray(s.red(), s.green(), s.blue());
+ }
+}
+
+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,
+ nullptr,
+ storeGenericFromRGBA64PM<QImage::Format_RGB32>,
+ storeARGB32FromRGBA64PM,
+ storeGenericFromRGBA64PM<QImage::Format_ARGB32_Premultiplied>,
+ storeGenericFromRGBA64PM<QImage::Format_RGB16>,
+ storeGenericFromRGBA64PM<QImage::Format_ARGB8565_Premultiplied>,
+ storeGenericFromRGBA64PM<QImage::Format_RGB666>,
+ storeGenericFromRGBA64PM<QImage::Format_ARGB6666_Premultiplied>,
+ storeGenericFromRGBA64PM<QImage::Format_RGB555>,
+ storeGenericFromRGBA64PM<QImage::Format_ARGB8555_Premultiplied>,
+ storeGenericFromRGBA64PM<QImage::Format_RGB888>,
+ storeGenericFromRGBA64PM<QImage::Format_RGB444>,
+ storeGenericFromRGBA64PM<QImage::Format_ARGB4444_Premultiplied>,
+ storeGenericFromRGBA64PM<QImage::Format_RGBX8888>,
+ storeRGBA8888FromRGBA64PM,
+ storeGenericFromRGBA64PM<QImage::Format_RGBA8888_Premultiplied>,
+ storeRGB30FromRGBA64PM<PixelOrderBGR>,
+ storeRGB30FromRGBA64PM<PixelOrderBGR>,
+ storeRGB30FromRGBA64PM<PixelOrderRGB>,
+ storeRGB30FromRGBA64PM<PixelOrderRGB>,
+ storeGenericFromRGBA64PM<QImage::Format_Alpha8>,
+ storeGenericFromRGBA64PM<QImage::Format_Grayscale8>,
+ storeRGBX64FromRGBA64PM,
+ storeRGBA64FromRGBA64PM,
+ 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
new file mode 100644
index 0000000000..14f19f4e74
--- /dev/null
+++ b/src/gui/painting/qpixellayout_p.h
@@ -0,0 +1,335 @@
+// 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
+
+//
+// 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/qimage.h>
+#include <QtGui/qrgba64.h>
+#include <QtGui/qrgbafloat.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+enum QtPixelOrder {
+ PixelOrderRGB,
+ PixelOrderBGR
+};
+
+template<enum QtPixelOrder> inline uint qConvertArgb32ToA2rgb30(QRgb);
+
+template<enum QtPixelOrder> inline uint qConvertRgb32ToRgb30(QRgb);
+
+template<enum QtPixelOrder> inline QRgb qConvertA2rgb30ToArgb32(uint c);
+
+// A combined unpremultiply and premultiply with new simplified alpha.
+// Needed when alpha loses precision relative to other colors during conversion (ARGB32 -> A2RGB30).
+template<unsigned int Shift>
+inline QRgb qRepremultiply(QRgb p)
+{
+ const uint alpha = qAlpha(p);
+ if (alpha == 255 || alpha == 0)
+ return p;
+ p = qUnpremultiply(p);
+ constexpr uint mult = 255 / (255 >> Shift);
+ const uint newAlpha = mult * (alpha >> Shift);
+ p = (p & ~0xff000000) | (newAlpha<<24);
+ return qPremultiply(p);
+}
+
+template<unsigned int Shift>
+inline QRgba64 qRepremultiply(QRgba64 p)
+{
+ const uint alpha = p.alpha();
+ if (alpha == 65535 || alpha == 0)
+ return p;
+ p = p.unpremultiplied();
+ constexpr uint mult = 65535 / (65535 >> Shift);
+ p.setAlpha(mult * (alpha >> Shift));
+ return p.premultiplied();
+}
+
+template<>
+inline uint qConvertArgb32ToA2rgb30<PixelOrderBGR>(QRgb c)
+{
+ c = qRepremultiply<6>(c);
+ return (c & 0xc0000000)
+ | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000))
+ | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
+ | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003));
+}
+
+template<>
+inline uint qConvertArgb32ToA2rgb30<PixelOrderRGB>(QRgb c)
+{
+ c = qRepremultiply<6>(c);
+ return (c & 0xc0000000)
+ | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000))
+ | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
+ | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003));
+}
+
+template<>
+inline uint qConvertRgb32ToRgb30<PixelOrderBGR>(QRgb c)
+{
+ return 0xc0000000
+ | (((c << 22) & 0x3fc00000) | ((c << 14) & 0x00300000))
+ | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
+ | (((c >> 14) & 0x000003fc) | ((c >> 22) & 0x00000003));
+}
+
+template<>
+inline uint qConvertRgb32ToRgb30<PixelOrderRGB>(QRgb c)
+{
+ return 0xc0000000
+ | (((c << 6) & 0x3fc00000) | ((c >> 2) & 0x00300000))
+ | (((c << 4) & 0x000ff000) | ((c >> 4) & 0x00000c00))
+ | (((c << 2) & 0x000003fc) | ((c >> 6) & 0x00000003));
+}
+
+template<>
+inline QRgb qConvertA2rgb30ToArgb32<PixelOrderBGR>(uint c)
+{
+ uint a = c >> 30;
+ a |= a << 2;
+ a |= a << 4;
+ return (a << 24)
+ | ((c << 14) & 0x00ff0000)
+ | ((c >> 4) & 0x0000ff00)
+ | ((c >> 22) & 0x000000ff);
+}
+
+template<>
+inline QRgb qConvertA2rgb30ToArgb32<PixelOrderRGB>(uint c)
+{
+ uint a = c >> 30;
+ a |= a << 2;
+ a |= a << 4;
+ return (a << 24)
+ | ((c >> 6) & 0x00ff0000)
+ | ((c >> 4) & 0x0000ff00)
+ | ((c >> 2) & 0x000000ff);
+}
+
+template<enum QtPixelOrder> inline QRgba64 qConvertA2rgb30ToRgb64(uint rgb);
+
+template<>
+inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderBGR>(uint rgb)
+{
+ quint16 alpha = rgb >> 30;
+ quint16 blue = (rgb >> 20) & 0x3ff;
+ quint16 green = (rgb >> 10) & 0x3ff;
+ quint16 red = rgb & 0x3ff;
+ // Expand the range.
+ alpha |= (alpha << 2);
+ alpha |= (alpha << 4);
+ alpha |= (alpha << 8);
+ red = (red << 6) | (red >> 4);
+ green = (green << 6) | (green >> 4);
+ blue = (blue << 6) | (blue >> 4);
+ return qRgba64(red, green, blue, alpha);
+}
+
+template<>
+inline QRgba64 qConvertA2rgb30ToRgb64<PixelOrderRGB>(uint rgb)
+{
+ quint16 alpha = rgb >> 30;
+ quint16 red = (rgb >> 20) & 0x3ff;
+ quint16 green = (rgb >> 10) & 0x3ff;
+ quint16 blue = rgb & 0x3ff;
+ // Expand the range.
+ alpha |= (alpha << 2);
+ alpha |= (alpha << 4);
+ alpha |= (alpha << 8);
+ red = (red << 6) | (red >> 4);
+ green = (green << 6) | (green >> 4);
+ blue = (blue << 6) | (blue >> 4);
+ return qRgba64(red, green, blue, alpha);
+}
+
+template<enum QtPixelOrder> inline unsigned int qConvertRgb64ToRgb30(QRgba64);
+
+template<>
+inline unsigned int qConvertRgb64ToRgb30<PixelOrderBGR>(QRgba64 c)
+{
+ c = qRepremultiply<14>(c);
+ const uint a = c.alpha() >> 14;
+ const uint r = c.red() >> 6;
+ const uint g = c.green() >> 6;
+ const uint b = c.blue() >> 6;
+ return (a << 30) | (b << 20) | (g << 10) | r;
+}
+
+template<>
+inline unsigned int qConvertRgb64ToRgb30<PixelOrderRGB>(QRgba64 c)
+{
+ c = qRepremultiply<14>(c);
+ const uint a = c.alpha() >> 14;
+ const uint r = c.red() >> 6;
+ const uint g = c.green() >> 6;
+ const uint b = c.blue() >> 6;
+ 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;
+ const uint rb = c & 0x3ff003ff;
+ return ag | (rb << 20) | (rb >> 20);
+}
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+static inline quint32 RGBA2ARGB(quint32 x) {
+ quint32 rgb = x >> 8;
+ quint32 a = x << 24;
+ return a | rgb;
+}
+
+static inline quint32 ARGB2RGBA(quint32 x) {
+ quint32 rgb = x << 8;
+ quint32 a = x >> 24;
+ return a | rgb;
+}
+#else
+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);
+}
+
+static inline quint32 ARGB2RGBA(quint32 x) {
+ return RGBA2ARGB(x);
+}
+#endif
+
+// We manually unalias the variables to make sure the compiler
+// fully optimizes both aliased and unaliased cases.
+#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \
+ if (src == buffer) { \
+ for (int i = 0; i < count; ++i) \
+ buffer[i] = conversion(buffer[i]); \
+ } else { \
+ for (int i = 0; i < count; ++i) \
+ buffer[i] = conversion(src[i]); \
+ }
+
+
+inline const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count)
+{
+ UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply);
+ return buffer;
+}
+
+inline const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count)
+{
+ UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));});
+ return buffer;
+}
+
+template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count);
+
+struct QDitherInfo {
+ int x;
+ int y;
+};
+
+typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const uchar *src,
+ int index, int count,
+ const QList<QRgb> *clut,
+ QDitherInfo *dither);
+typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index,
+ int count, const QList<QRgb> *clut,
+ QDitherInfo *dither);
+
+typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src,
+ int index, int count,
+ const QList<QRgb> *clut,
+ QDitherInfo *dither);
+typedef void(QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index,
+ int count, const QList<QRgb> *clut,
+ QDitherInfo *dither);
+
+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);
+
+struct QPixelLayout
+{
+ // Bits per pixel
+ enum BPP {
+ BPPNone,
+ BPP1MSB,
+ BPP1LSB,
+ BPP8,
+ BPP16,
+ BPP24,
+ BPP32,
+ BPP64,
+ BPP16FPx4,
+ BPP32FPx4,
+ BPPCount
+ };
+
+ bool hasAlphaChannel;
+ bool premultiplied;
+ BPP bpp;
+ RbSwapFunc rbSwap;
+ ConvertFunc convertToARGB32PM;
+ ConvertTo64Func convertToRGBA64PM;
+ FetchAndConvertPixelsFunc fetchToARGB32PM;
+ FetchAndConvertPixelsFunc64 fetchToRGBA64PM;
+ ConvertAndStorePixelsFunc storeFromARGB32PM;
+ ConvertAndStorePixelsFunc storeFromRGB32;
+};
+
+extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[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];
+
+QT_END_NAMESPACE
+
+#endif // QPIXELLAYOUT_P_H
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index c092a7153f..f7c4df40c8 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -1,82 +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 "qplatformbackingstore.h"
#include <qwindow.h>
#include <qpixmap.h>
+#include <private/qbackingstorerhisupport_p.h>
+#include <private/qbackingstoredefaultcompositor_p.h>
#include <private/qwindow_p.h>
-#include <qopengl.h>
-#include <qopenglcontext.h>
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QOpenGLShaderProgram>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLFunctions>
-#ifndef QT_NO_OPENGL
-#include <QtGui/qopengltextureblitter.h>
-#include <QtGui/qoffscreensurface.h>
-#endif
-#include <qpa/qplatformgraphicsbuffer.h>
-#include <qpa/qplatformgraphicsbufferhelper.h>
-
-#ifndef GL_TEXTURE_BASE_LEVEL
-#define GL_TEXTURE_BASE_LEVEL 0x813C
-#endif
-#ifndef GL_TEXTURE_MAX_LEVEL
-#define GL_TEXTURE_MAX_LEVEL 0x813D
-#endif
-#ifndef GL_UNPACK_ROW_LENGTH
-#define GL_UNPACK_ROW_LENGTH 0x0CF2
-#endif
-#ifndef GL_RGB10_A2
-#define GL_RGB10_A2 0x8059
-#endif
-#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#endif
-
-#ifndef GL_FRAMEBUFFER_SRGB
-#define GL_FRAMEBUFFER_SRGB 0x8DB9
-#endif
-#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE
-#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA
-#endif
+#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
@@ -88,53 +20,30 @@ public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
, backingStore(nullptr)
-#ifndef QT_NO_OPENGL
- , textureId(0)
- , blitter(nullptr)
-#endif
{
}
- ~QPlatformBackingStorePrivate()
- {
-#ifndef QT_NO_OPENGL
- if (context) {
- QOffscreenSurface offscreenSurface;
- offscreenSurface.setFormat(context->format());
- offscreenSurface.create();
- context->makeCurrent(&offscreenSurface);
- if (textureId)
- context->functions()->glDeleteTextures(1, &textureId);
- if (blitter)
- blitter->destroy();
- }
- delete blitter;
-#endif
- }
QWindow *window;
QBackingStore *backingStore;
-#ifndef QT_NO_OPENGL
- QScopedPointer<QOpenGLContext> context;
- mutable GLuint textureId;
- mutable QSize textureSize;
- mutable bool needsSwizzle;
- mutable bool premultiplied;
- QOpenGLTextureBlitter *blitter;
-#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
{
@@ -144,7 +53,7 @@ public:
{
}
- QVector<QBackingstoreTextureInfo> textures;
+ QList<QBackingstoreTextureInfo> textures;
bool locked;
};
@@ -160,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)
@@ -208,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;
@@ -226,7 +157,6 @@ void QPlatformTextureList::clear()
Q_D(QPlatformTextureList);
d->textures.clear();
}
-#endif // QT_NO_OPENGL
/*!
\class QPlatformBackingStore
@@ -239,275 +169,81 @@ void QPlatformTextureList::clear()
windows.
*/
-#ifndef QT_NO_OPENGL
-
-static inline QRect deviceRect(const QRect &rect, QWindow *window)
-{
- QRect deviceRect(rect.topLeft() * window->devicePixelRatio(),
- rect.size() * window->devicePixelRatio());
- return deviceRect;
-}
-
-static inline QPoint deviceOffset(const QPoint &pt, QWindow *window)
-{
- return pt * window->devicePixelRatio();
-}
-
-static QRegion deviceRegion(const QRegion &region, QWindow *window, const QPoint &offset)
-{
- if (offset.isNull() && window->devicePixelRatio() <= 1)
- return region;
+/*!
+ Flushes the given \a region from the specified \a window.
- QVector<QRect> rects;
- rects.reserve(region.rectCount());
- for (const QRect &rect : region)
- rects.append(deviceRect(rect.translated(offset), 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.
- QRegion deviceRegion;
- deviceRegion.setRects(rects.constData(), rects.count());
- return deviceRegion;
-}
+ 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.
-static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
-{
- return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
- topLeftRect.width(), topLeftRect.height());
-}
-
-static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect,
- QOpenGLTextureBlitter *blitter, const QPoint &offset, bool canUseSrgb)
+ \sa rhiFlush()
+ */
+void QPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
- const QRect clipRect = textures->clipRect(idx);
- if (clipRect.isEmpty())
- return;
-
- 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());
-
- const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window),
- deviceWindowRect);
-
- const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window),
- deviceRect(rectInWindow, window).size(),
- QOpenGLTextureBlitter::OriginBottomLeft);
-
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- const bool srgb = textures->flags(idx).testFlag(QPlatformTextureList::TextureIsSrgb);
- if (srgb && canUseSrgb)
- funcs->glEnable(GL_FRAMEBUFFER_SRGB);
-
- blitter->blit(textures->textureId(idx), target, source);
-
- if (srgb && canUseSrgb)
- funcs->glDisable(GL_FRAMEBUFFER_SRGB);
+ Q_UNUSED(window);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
}
/*!
- Flushes the given \a region from the specified \a window onto the
- screen, and composes it with the specified \a textures.
+ 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 OpenGL. May be reimplemented in subclasses if there
- is a more efficient native way to do it.
+ 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)
-{
- if (!qt_window_private(window)->receivedExpose)
- return;
-
- if (!d_ptr->context) {
- d_ptr->context.reset(new QOpenGLContext);
- d_ptr->context->setFormat(d_ptr->window->requestedFormat());
- d_ptr->context->setScreen(d_ptr->window->screen());
- d_ptr->context->setShareContext(qt_window_private(d_ptr->window)->shareContext());
- if (!d_ptr->context->create()) {
- qCWarning(lcQpaBackingStore, "composeAndFlush: QOpenGLContext creation failed");
- return;
- }
- }
-
- bool current = d_ptr->context->makeCurrent(window);
-
- if (!current && !d_ptr->context->isValid()) {
- delete d_ptr->blitter;
- d_ptr->blitter = nullptr;
- d_ptr->textureId = 0;
- current = d_ptr->context->create() && d_ptr->context->makeCurrent(window);
- }
-
- if (!current) {
- qCWarning(lcQpaBackingStore, "composeAndFlush: makeCurrent() failed");
- return;
- }
-
- qCDebug(lcQpaBackingStore) << "Composing and flushing" << region << "of" << window
- << "at offset" << offset << "with" << textures->count() << "texture(s) in" << textures;
-
- QWindowPrivate::get(window)->lastComposeTime.start();
-
- QOpenGLFunctions *funcs = d_ptr->context->functions();
- funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio()));
- funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
- funcs->glClear(GL_COLOR_BUFFER_BIT);
- if (!d_ptr->blitter) {
- d_ptr->blitter = new QOpenGLTextureBlitter;
- d_ptr->blitter->create();
- }
-
- d_ptr->blitter->bind();
-
- const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
- const QPoint deviceWindowOffset = deviceOffset(offset, window);
-
- bool canUseSrgb = false;
- // If there are any sRGB textures in the list, check if the destination
- // framebuffer is sRGB capable.
- for (int i = 0; i < textures->count(); ++i) {
- if (textures->flags(i).testFlag(QPlatformTextureList::TextureIsSrgb)) {
- GLint cap = 0;
- funcs->glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE, &cap);
- if (cap)
- canUseSrgb = true;
- break;
- }
- }
-
- // Textures for renderToTexture widgets.
- for (int i = 0; i < textures->count(); ++i) {
- if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
- }
-
- // Backingstore texture with the normal widgets.
- GLuint textureId = 0;
- QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
- if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) {
- if (graphicsBuffer->size() != d_ptr->textureSize) {
- if (d_ptr->textureId)
- funcs->glDeleteTextures(1, &d_ptr->textureId);
- funcs->glGenTextures(1, &d_ptr->textureId);
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- }
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied)) {
- d_ptr->textureSize = graphicsBuffer->size();
- } else {
- d_ptr->textureSize = QSize(0,0);
- }
-
- graphicsBuffer->unlock();
- } else if (!region.isEmpty()){
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied);
- graphicsBuffer->unlock();
- }
-
- if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
- origin = QOpenGLTextureBlitter::OriginBottomLeft;
- textureId = d_ptr->textureId;
- } else {
- TextureFlags flags;
- textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags);
- d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0;
- d_ptr->premultiplied = (flags & TexturePremultiplied) != 0;
- if (flags & TextureFlip)
- origin = QOpenGLTextureBlitter::OriginBottomLeft;
- }
-
- funcs->glEnable(GL_BLEND);
- if (d_ptr->premultiplied)
- funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
- else
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
-
- if (textureId) {
- if (d_ptr->needsSwizzle)
- d_ptr->blitter->setRedBlueSwizzle(true);
- // The backingstore is for the entire tlw.
- // In case of native children offset tells the position relative to the tlw.
- const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(deviceWindowOffset), d_ptr->textureSize.height());
- const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect,
- d_ptr->textureSize,
- origin);
- d_ptr->blitter->blit(textureId, QMatrix4x4(), source);
- if (d_ptr->needsSwizzle)
- d_ptr->blitter->setRedBlueSwizzle(false);
- }
-
- // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
- bool blendIsPremultiplied = d_ptr->premultiplied;
- for (int i = 0; i < textures->count(); ++i) {
- const QPlatformTextureList::Flags flags = textures->flags(i);
- if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) {
- if (!blendIsPremultiplied) {
- funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
- blendIsPremultiplied = true;
- }
- } else {
- if (blendIsPremultiplied) {
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
- blendIsPremultiplied = false;
- }
- }
- if (flags.testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
- }
-
- funcs->glDisable(GL_BLEND);
- d_ptr->blitter->release();
-
- d_ptr->context->swapBuffers(window);
+ \sa flush()
+ */
+QPlatformBackingStore::FlushResult QPlatformBackingStore::rhiFlush(QWindow *window,
+ qreal sourceDevicePixelRatio,
+ const QRegion &region,
+ const QPoint &offset,
+ QPlatformTextureList *textures,
+ bool translucentBackground)
+{
+ 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
@@ -521,142 +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
-{
- Q_ASSERT(textureSize);
- Q_ASSERT(flags);
-
- QImage image = toImage();
- QSize imageSize = image.size();
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- GLenum internalFormat = GL_RGBA;
- GLuint pixelType = GL_UNSIGNED_BYTE;
-
- bool needsConversion = false;
- *flags = { };
- switch (image.format()) {
- case QImage::Format_ARGB32_Premultiplied:
- *flags |= TexturePremultiplied;
- Q_FALLTHROUGH();
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- *flags |= TextureSwizzle;
- break;
- case QImage::Format_RGBA8888_Premultiplied:
- *flags |= TexturePremultiplied;
- Q_FALLTHROUGH();
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- break;
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- internalFormat = GL_RGB10_A2;
- *flags |= TexturePremultiplied;
- } else {
- needsConversion = true;
- }
- break;
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- internalFormat = GL_RGB10_A2;
- *flags |= TextureSwizzle | TexturePremultiplied;
- } else {
- needsConversion = true;
- }
- break;
- default:
- needsConversion = true;
- break;
- }
- if (imageSize.isEmpty()) {
- *textureSize = imageSize;
- return 0;
- }
-
- // Must rely on the input only, not d_ptr.
- // With the default composeAndFlush() textureSize is &d_ptr->textureSize.
- bool resized = *textureSize != imageSize;
- if (dirtyRegion.isEmpty() && !resized)
- return d_ptr->textureId;
-
- *textureSize = imageSize;
-
- if (needsConversion)
- image = image.convertToFormat(QImage::Format_RGBA8888);
-
- // The image provided by the backingstore may have a stride larger than width * 4, for
- // instance on platforms that manually implement client-side decorations.
- static const int bytesPerPixel = 4;
- const int strideInPixels = image.bytesPerLine() / bytesPerPixel;
- const bool hasUnpackRowLength = !ctx->isOpenGLES() || ctx->format().majorVersion() >= 3;
-
- QOpenGLFunctions *funcs = ctx->functions();
-
- if (hasUnpackRowLength) {
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, strideInPixels);
- } else if (strideInPixels != image.width()) {
- // No UNPACK_ROW_LENGTH on ES 2.0 and yet we would need it. This case is typically
- // hit with QtWayland which is rarely used in combination with a ES2.0-only GL
- // implementation. Therefore, accept the performance hit and do a copy.
- image = image.copy();
- }
-
- if (resized) {
- if (d_ptr->textureId)
- funcs->glDeleteTextures(1, &d_ptr->textureId);
- funcs->glGenTextures(1, &d_ptr->textureId);
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- }
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, imageSize.width(), imageSize.height(), 0, GL_RGBA, pixelType,
- const_cast<uchar*>(image.constBits()));
- } else {
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QRect imageRect = image.rect();
- QRect rect = dirtyRegion.boundingRect() & imageRect;
-
- if (hasUnpackRowLength) {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.constScanLine(rect.y()) + rect.x() * bytesPerPixel);
- } else {
- // if the rect is wide enough it's cheaper to just
- // extend it instead of doing an image copy
- if (rect.width() >= imageRect.width() / 2) {
- rect.setX(0);
- rect.setWidth(imageRect.width());
- }
-
- // if the sub-rect is full-width we can pass the image data directly to
- // OpenGL instead of copying, since there's no gap between scanlines
-
- if (rect.width() == imageRect.width()) {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.constScanLine(rect.y()));
- } else {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.copy(rect).constBits());
- }
- }
- }
-
- if (hasUnpackRowLength)
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-
- return d_ptr->textureId;
+QRhiTexture *QPlatformBackingStore::toTexture(QRhiResourceUpdateBatch *resourceUpdates,
+ const QRegion &dirtyRegion,
+ TextureFlags *flags) const
+{
+ return d_ptr->compositor.toTexture(this, d_ptr->rhiSupport.rhi(), resourceUpdates, dirtyRegion, flags);
}
-#endif // QT_NO_OPENGL
/*!
\fn QPaintDevice* QPlatformBackingStore::paintDevice()
@@ -750,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 7aa054f1e2..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,24 +20,71 @@
#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;
class QPoint;
class QImage;
class QPlatformBackingStorePrivate;
-class QPlatformWindow;
class QPlatformTextureList;
class QPlatformTextureListPrivate;
-class QOpenGLContext;
class QPlatformGraphicsBuffer;
+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
@@ -82,7 +93,8 @@ public:
enum Flag {
StacksOnTop = 0x01,
TextureIsSrgb = 0x02,
- NeedsPremultipliedAlphaBlending = 0x04
+ NeedsPremultipliedAlphaBlending = 0x04,
+ MirrorVertically = 0x08
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -91,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);
@@ -99,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();
@@ -107,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();
@@ -120,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;
@@ -146,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;
@@ -153,9 +183,7 @@ private:
friend class QBackingStore;
};
-#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 3bf6004fcc..d615245eb4 100644
--- a/src/gui/painting/qpolygon.cpp
+++ b/src/gui/painting/qpolygon.cpp
@@ -1,48 +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 "qpolygon.h"
#include "qrect.h"
#include "qdatastream.h"
-#include "qmatrix.h"
#include "qdebug.h"
#include "qpainterpath.h"
+#include "qtransform.h"
#include "qvariant.h"
#include "qpainterpath_p.h"
#include "qbezier_p.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
@@ -111,13 +75,13 @@ static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QP
from a specified index (resizing the polygon if necessary).
QPolygon provides the boundingRect() and translate() functions for
- geometry functions. Use the QMatrix::map() function for more
+ geometry functions. Use the QTransform::map() function for more
general transformations of QPolygons.
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,15 +434,15 @@ 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 QMatrix::map() function for more general
+ operations. Use the QTransform::map() function for more general
transformations of QPolygonFs.
QPolygonF also provides the isClosed() function to determine
@@ -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(QVariant::Polygon, 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 93fab55aa1..f2f5d48395 100644
--- a/src/gui/painting/qpolygon.h
+++ b/src/gui/painting/qpolygon.h
@@ -1,105 +1,66 @@
-/****************************************************************************
-**
-** 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
#include <QtGui/qtguiglobal.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
QT_BEGIN_NAMESPACE
-
-class QMatrix;
class QTransform;
class QRect;
class QVariant;
-class Q_GUI_EXPORT QPolygon : public QVector<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 QVector<QPoint> &v) : QVector<QPoint>(v) {}
- /*implicit*/ QPolygon(QVector<QPoint> &&v) noexcept : QVector<QPoint>(std::move(v)) {}
- QPolygon(const QRect &r, bool closed=false);
- QPolygon(int nPoints, const int *points);
- QPolygon(const QPolygon &other) : QVector<QPoint>(other) {}
- QPolygon(QPolygon &&other) noexcept : QVector<QPoint>(std::move(other)) {}
- QPolygon &operator=(QPolygon &&other) noexcept { swap(other); return *this; }
- QPolygon &operator=(const QPolygon &other) { QVector<QPoint>::operator=(other); return *this; }
- void swap(QPolygon &other) noexcept { QVector<QPoint>::swap(other); } // prevent QVector<QPoint><->QPolygon swaps
-
- operator QVariant() const;
-
- void translate(int dx, int dy);
+ 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
+
+ Q_GUI_EXPORT operator QVariant() const;
+
+ 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);
- bool containsPoint(const QPoint &pt, Qt::FillRule fillRule) const;
+ Q_GUI_EXPORT bool containsPoint(const QPoint &pt, Qt::FillRule fillRule) 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;
+ [[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;
- bool intersects(const QPolygon &r) const;
-};
-Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QPolygon)
+ Q_GUI_EXPORT bool intersects(const QPolygon &r) const;
-inline QPolygon::QPolygon(int asize) : QVector<QPoint>(asize) {}
+ [[nodiscard]] inline QPolygonF toPolygonF() const;
+};
+Q_DECLARE_SHARED(QPolygon)
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QPolygon &);
@@ -118,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); }
@@ -134,47 +92,42 @@ inline QPolygon QPolygon::translated(const QPoint &offset) const
class QRectF;
-class Q_GUI_EXPORT QPolygonF : public QVector<QPointF>
+class QPolygonF : public QList<QPointF>
{
public:
- inline QPolygonF() {}
- inline ~QPolygonF() {}
- inline explicit QPolygonF(int size);
- inline /*implicit*/ QPolygonF(const QVector<QPointF> &v) : QVector<QPointF>(v) {}
- /* implicit */ QPolygonF(QVector<QPointF> &&v) noexcept : QVector<QPointF>(std::move(v)) {}
- QPolygonF(const QRectF &r);
- /*implicit*/ QPolygonF(const QPolygon &a);
- inline QPolygonF(const QPolygonF &a) : QVector<QPointF>(a) {}
- QPolygonF(QPolygonF &&other) noexcept : QVector<QPointF>(std::move(other)) {}
- QPolygonF &operator=(QPolygonF &&other) noexcept { swap(other); return *this; }
- QPolygonF &operator=(const QPolygonF &other) { QVector<QPointF>::operator=(other); return *this; }
- inline void swap(QPolygonF &other) { QVector<QPointF>::swap(other); } // prevent QVector<QPointF><->QPolygonF swaps
-
- operator QVariant() const;
+ 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
+
+ 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_NOT_MOVABLE_UNTIL_QT6(QPolygonF)
+Q_DECLARE_SHARED(QPolygonF)
-inline QPolygonF::QPolygonF(int asize) : QVector<QPointF>(asize) {}
+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/qrasterbackingstore.cpp b/src/gui/painting/qrasterbackingstore.cpp
new file mode 100644
index 0000000000..3b3ef2fd2e
--- /dev/null
+++ b/src/gui/painting/qrasterbackingstore.cpp
@@ -0,0 +1,83 @@
+// 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"
+
+#include <QtGui/qbackingstore.h>
+#include <QtGui/qpainter.h>
+
+#include <private/qhighdpiscaling_p.h>
+#include <qpa/qplatformwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+QRasterBackingStore::QRasterBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+{
+}
+
+QRasterBackingStore::~QRasterBackingStore()
+{
+}
+
+void QRasterBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents);
+ m_requestedSize = size;
+}
+
+QImage::Format QRasterBackingStore::format() const
+{
+ if (window()->format().hasAlpha())
+ return QImage::Format_ARGB32_Premultiplied;
+ else
+ return QImage::Format_RGB32;
+}
+
+QPaintDevice *QRasterBackingStore::paintDevice()
+{
+ return &m_image;
+}
+
+QImage QRasterBackingStore::toImage() const
+{
+ return m_image;
+}
+
+bool QRasterBackingStore::scroll(const QRegion &region, int dx, int dy)
+{
+ if (!QPlatformSurface::isRasterSurface(window()))
+ return false;
+
+ extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
+
+ const qreal devicePixelRatio = m_image.devicePixelRatio();
+ const QPoint delta(dx * devicePixelRatio, dy * devicePixelRatio);
+
+ const QRect rect = region.boundingRect();
+ qt_scrollRectInImage(m_image, QRect(rect.topLeft() * devicePixelRatio, rect.size() * devicePixelRatio), delta);
+
+ return true;
+}
+
+void QRasterBackingStore::beginPaint(const QRegion &region)
+{
+ qreal nativeWindowDevicePixelRatio = window()->handle()->devicePixelRatio();
+ QSize effectiveBufferSize = m_requestedSize * nativeWindowDevicePixelRatio;
+ if (m_image.devicePixelRatio() != nativeWindowDevicePixelRatio || m_image.size() != effectiveBufferSize) {
+ m_image = QImage(effectiveBufferSize, format());
+ m_image.setDevicePixelRatio(nativeWindowDevicePixelRatio);
+ if (m_image.hasAlphaChannel())
+ m_image.fill(Qt::transparent);
+ }
+
+ if (!m_image.hasAlphaChannel())
+ return;
+
+ QPainter painter(&m_image);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ for (const QRect &rect : region)
+ painter.fillRect(rect, Qt::transparent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qrasterbackingstore_p.h b/src/gui/painting/qrasterbackingstore_p.h
new file mode 100644
index 0000000000..be8d122655
--- /dev/null
+++ b/src/gui/painting/qrasterbackingstore_p.h
@@ -0,0 +1,46 @@
+// 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
+
+//
+// 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 <private/qglobal_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QRasterBackingStore : public QPlatformBackingStore
+{
+public:
+ QRasterBackingStore(QWindow *window);
+ ~QRasterBackingStore();
+
+ void resize(const QSize &size, const QRegion &staticContents) override;
+ bool scroll(const QRegion &area, int dx, int dy) override;
+ void beginPaint(const QRegion &region) override;
+
+ QPaintDevice *paintDevice() override;
+ QImage toImage() const override;
+
+protected:
+ virtual QImage::Format format() const;
+
+ QImage m_image;
+ QSize m_requestedSize;
+};
+
+QT_END_NAMESPACE
+
+#endif // QRASTERBACKINGSTORE_P_H
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 cd31d75f83..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"
@@ -46,19 +10,26 @@
#include <private/qdatabuffer_p.h>
#include <private/qdrawhelper_p.h>
+#include <QtGui/qpainterpath.h>
+
#include <algorithm>
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
@@ -86,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());
@@ -129,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,
@@ -138,8 +110,8 @@ public:
struct Line
{
- Q16Dot16 x;
- Q16Dot16 delta;
+ QScFixed x;
+ QScFixed delta;
int top, bottom;
@@ -155,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();
@@ -173,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;
@@ -189,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;
@@ -221,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;
}
@@ -299,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
+template <bool AllVertical>
+void QScanConverter::scanConvert()
{
- 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)
-{
- 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;
@@ -371,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()
@@ -396,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();
@@ -423,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);
}
@@ -525,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;
@@ -539,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)
@@ -553,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 };
@@ -570,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) {
@@ -599,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 };
@@ -620,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;
@@ -643,7 +592,6 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b)
QRasterizer::QRasterizer()
: d(new QRasterizerPrivate)
{
- d->legacyRounding = false;
}
QRasterizer::~QRasterizer()
@@ -667,44 +615,44 @@ void QRasterizer::setClipRect(const QRect &clipRect)
d->clipRect = clipRect;
}
-void QRasterizer::setLegacyRoundingEnabled(bool legacyRoundingEnabled)
-{
- d->legacyRounding = legacyRoundingEnabled;
-}
-
-static Q16Dot16 intersectPixelFP(int x, Q16Dot16 top, Q16Dot16 bottom, Q16Dot16 leftIntersectX, Q16Dot16 rightIntersectX, Q16Dot16 slope, Q16Dot16 invSlope)
+static QScFixed intersectPixelFP(int x, QScFixed top, QScFixed bottom, QScFixed leftIntersectX, QScFixed rightIntersectX, QScFixed slope, QScFixed 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 {
@@ -743,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)
@@ -769,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
@@ -864,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;
@@ -900,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
@@ -969,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());
@@ -1084,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;
}
@@ -1144,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
@@ -1154,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;
@@ -1171,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; \
@@ -1207,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) {
@@ -1245,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 42e88889a1..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
@@ -538,8 +502,8 @@ int QRBTree<T>::order(Node *left, Node *right)
if (left == right)
return 0;
- QVector<Node *> leftAncestors;
- QVector<Node *> rightAncestors;
+ QList<Node *> leftAncestors;
+ QList<Node *> rightAncestors;
while (left) {
leftAncestors.push_back(left);
left = left->parent;
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 783b02fb93..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"
@@ -46,9 +10,15 @@
#include "qvarlengtharray.h"
#include "qimage.h"
#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
/*!
@@ -81,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.
@@ -129,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.
@@ -295,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));
}
@@ -344,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;
@@ -428,9 +398,6 @@ QDebug operator<<(QDebug s, const QRegion &r)
\sa united(), operator+()
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator|(const QRegion &r) const
{ return united(r); }
@@ -440,9 +407,6 @@ QRegion QRegion::operator|(const QRegion &r) const
\sa united(), operator|()
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator+(const QRegion &r) const
{ return united(r); }
@@ -450,9 +414,6 @@ QRegion QRegion::operator+(const QRegion &r) const
\overload
\since 4.4
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator+(const QRect &r) const
{ return united(r); }
@@ -462,9 +423,6 @@ QRegion QRegion::operator+(const QRect &r) const
\sa intersected()
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator&(const QRegion &r) const
{ return intersected(r); }
@@ -472,9 +430,6 @@ QRegion QRegion::operator&(const QRegion &r) const
\overload
\since 4.4
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator&(const QRect &r) const
{
return intersected(r);
@@ -486,9 +441,6 @@ QRegion QRegion::operator&(const QRect &r) const
\sa subtracted()
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator-(const QRegion &r) const
{ return subtracted(r); }
@@ -498,9 +450,6 @@ QRegion QRegion::operator-(const QRegion &r) const
\sa xored()
*/
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
-const
-#endif
QRegion QRegion::operator^(const QRegion &r) const
{ return xored(r); }
@@ -599,7 +548,7 @@ QRegion& QRegion::operator^=(const QRegion &r)
*/
QRegion::operator QVariant() const
{
- return QVariant(QVariant::Region, this);
+ return QVariant::fromValue(*this);
}
/*!
@@ -687,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
@@ -743,21 +692,6 @@ QRegion QRegion::intersect(const QRect &r) const
*/
/*!
- \fn QRegion QRegion::unite(const QRegion &r) const
- \obsolete
-
- Use united(\a r) instead.
-*/
-
-/*!
- \fn QRegion QRegion::unite(const QRect &rect) const
- \since 4.4
- \obsolete
-
- Use united(\a rect) instead.
-*/
-
-/*!
\fn QRegion QRegion::united(const QRect &rect) const
\since 4.4
@@ -780,21 +714,6 @@ QRegion QRegion::intersect(const QRect &r) const
*/
/*!
- \fn QRegion QRegion::intersect(const QRegion &r) const
- \obsolete
-
- Use intersected(\a r) instead.
-*/
-
-/*!
- \fn QRegion QRegion::intersect(const QRect &rect) const
- \since 4.4
- \obsolete
-
- Use intersected(\a rect) instead.
-*/
-
-/*!
\fn QRegion QRegion::intersected(const QRect &rect) const
\since 4.4
@@ -817,13 +736,6 @@ QRegion QRegion::intersect(const QRect &r) const
*/
/*!
- \fn QRegion QRegion::subtract(const QRegion &r) const
- \obsolete
-
- Use subtracted(\a r) instead.
-*/
-
-/*!
\fn QRegion QRegion::subtracted(const QRegion &r) const
\since 4.2
@@ -838,13 +750,6 @@ QRegion QRegion::intersect(const QRect &r) const
*/
/*!
- \fn QRegion QRegion::eor(const QRegion &r) const
- \obsolete
-
- Use xored(\a r) instead.
-*/
-
-/*!
\fn QRegion QRegion::xored(const QRegion &r) const
\since 4.2
@@ -865,20 +770,6 @@ QRegion QRegion::intersect(const QRect &r) const
gives a rectangle that is QRect::isNull().
*/
-#if QT_DEPRECATED_SINCE(5, 11)
-/*!
- \fn QVector<QRect> QRegion::rects() const
- \obsolete
-
- Use begin() and end() instead.
-
- Returns an array of non-overlapping rectangles that make up the
- region.
-
- The union of all the rectangles is equal to the original region.
-*/
-#endif
-
/*!
\typedef QRegion::const_iterator
\since 5.8
@@ -1179,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;
@@ -2251,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;
@@ -2844,7 +2735,7 @@ static bool RectInRegion(QRegionPrivate *region, int rx, int ry, uint rwidth, ui
break;
}
}
- return partIn ? ((ry <= prect->bottom()) ? RectanglePart : RectangleIn) : RectangleOut;
+ return partIn;
}
// END OF Region.c extract
// START OF poly.h extract
@@ -3300,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
@@ -3560,7 +3450,7 @@ static void PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
int extendTo = 0;
bool needsExtend = false;
QVarLengthArray<QRegionSpan> row;
- int rowSize = 0;
+ qsizetype rowSize = 0;
reg->extents.setLeft(INT_MAX);
reg->extents.setRight(INT_MIN);
@@ -3643,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 */
@@ -3924,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) {
@@ -3986,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);
@@ -3994,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;
}
@@ -4311,20 +4204,6 @@ bool qt_region_strictContains(const QRegion &region, const QRect &rect)
&& rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
}
-#if QT_DEPRECATED_SINCE(5, 11)
-QVector<QRect> QRegion::rects() const
-{
- if (d->qt_rgn) {
- d->qt_rgn->vectorize();
- d->qt_rgn->rects.reserve(d->qt_rgn->numRects);
- d->qt_rgn->rects.resize(d->qt_rgn->numRects);
- return d->qt_rgn->rects;
- } else {
- return QVector<QRect>();
- }
-}
-#endif
-
QRegion::const_iterator QRegion::begin() const noexcept
{
return d->qt_rgn ? d->qt_rgn->begin() : nullptr;
@@ -4406,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 54de916198..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
@@ -44,6 +8,7 @@
#include <QtCore/qatomic.h>
#include <QtCore/qrect.h>
#include <QtGui/qwindowdefs.h>
+#include <QtCore/qcontainerfwd.h>
#ifndef QT_NO_DATASTREAM
#include <QtCore/qdatastream.h>
@@ -52,7 +17,6 @@
QT_BEGIN_NAMESPACE
-template <class T> class QVector;
class QVariant;
struct QRegionPrivate;
@@ -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,45 +60,23 @@ 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()); }
-
- 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;
-
-#if QT_DEPRECATED_SINCE(5, 0)
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion unite(const QRegion &r) const { return united(r); }
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion unite(const QRect &r) const { return united(r); }
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion intersect(const QRegion &r) const { return intersected(r); }
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion intersect(const QRect &r) const { return intersected(r); }
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion subtract(const QRegion &r) const { return subtracted(r); }
- Q_REQUIRED_RESULT inline QT_DEPRECATED QRegion eor(const QRegion &r) const { return xored(r); }
-#endif
+ [[nodiscard]] QRegion translated(int dx, int dy) const;
+ [[nodiscard]] inline QRegion translated(const QPoint &p) const { return translated(p.x(), p.y()); }
+
+ [[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;
QRect boundingRect() const noexcept;
-#if QT_DEPRECATED_SINCE(5, 11)
- QT_DEPRECATED_X("Use begin()/end() instead")
- QVector<QRect> rects() const;
-#endif
void setRects(const QRect *rect, int num);
int rectCount() const noexcept;
-#ifdef Q_COMPILER_MANGLES_RETURN_TYPE
- // ### Qt 6: remove these, they're kept for MSVC compat
- const QRegion operator|(const QRegion &r) const;
- const QRegion operator+(const QRegion &r) const;
- const QRegion operator+(const QRect &r) const;
- const QRegion operator&(const QRegion &r) const;
- const QRegion operator&(const QRect &r) const;
- const QRegion operator-(const QRegion &r) const;
- const QRegion operator^(const QRegion &r) const;
-#else
+
QRegion operator|(const QRegion &r) const;
QRegion operator+(const QRegion &r) const;
QRegion operator+(const QRect &r) const;
@@ -143,7 +84,7 @@ public:
QRegion operator&(const QRect &r) const;
QRegion operator-(const QRegion &r) const;
QRegion operator^(const QRegion &r) const;
-#endif // Q_COMPILER_MANGLES_RETURN_TYPE
+
QRegion& operator|=(const QRegion &r);
QRegion& operator+=(const QRegion &r);
QRegion& operator+=(const QRect &r);
@@ -156,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 &);
@@ -179,7 +126,7 @@ Q_GUI_EXPORT
static const struct QRegionData shared_empty;
static void cleanUp(QRegionData *x);
};
-Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QRegion)
+Q_DECLARE_SHARED(QRegion)
/*****************************************************************************
QRegion stream functions
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 0e0b567890..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,23 +136,23 @@ public:
#endif
}
- Q_DECL_CONSTEXPR operator quint64() const
+ constexpr operator quint64() const
{
return rgba;
}
- QRgba64 operator=(quint64 _rgba)
+ QRgba64 &operator=(quint64 _rgba) noexcept
{
rgba = _rgba;
return *this;
}
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 3207f1944b..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);
@@ -263,10 +231,11 @@ public:
QStroker *stroker() const { return m_stroker; }
- static QVector<qfixed> patternForStyle(Qt::PenStyle style);
+ static QList<qfixed> patternForStyle(Qt::PenStyle style);
+ static int repetitionLimit() { return 10000; }
- void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
- QVector<qfixed> dashPattern() const { return m_dashPattern; }
+ void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
+ QList<qfixed> dashPattern() const { return m_dashPattern; }
void setDashOffset(qreal offset) { m_dashOffset = offset; }
qreal dashOffset() const { return m_dashOffset; }
@@ -281,7 +250,7 @@ protected:
void processCurrentSubpath() override;
QStroker *m_stroker;
- QVector<qfixed> m_dashPattern;
+ QList<qfixed> m_dashPattern;
qreal m_dashOffset;
qreal m_stroke_width;
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index 7b16e8c211..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,23 +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>"
- },
- {
- "Id": "webgradients",
- "Name": "WebGradients",
- "QDocModule": "qtgui",
- "QtUsage": "Used in Qt GUI to provide presets for QGradient.",
- "Files": "webgradients.css",
-
- "Description": "WebGradients is a free collection of 180 linear gradients.",
- "Homepage": "https://webgradients.com/",
- "License": "MIT License",
- "LicenseId": "MIT",
- "LicenseFile": "WEBGRADIENTS_LICENSE.txt",
- "Copyright": "Copyright (c) 2017 itmeo"
+ "Copyright": ["Copyright (C) 2004, 2005 Daniel M. Duley.",
+ "(C) Carsten Haitzler and various contributors.",
+ "(C) Willem Monsuwe <willem@stack.nl>"]
},
{
"Id": "xserverhelper",
@@ -54,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 f40ca9d8b4..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>
@@ -43,6 +7,8 @@
#include "private/qfontengine_p.h"
#include "private/qnumeric_p.h"
+#include <QtGui/qpainterpath.h>
+
QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
@@ -62,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;
@@ -90,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
@@ -103,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++]);
}
@@ -118,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)))
@@ -261,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:
@@ -315,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);
@@ -341,15 +324,16 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
} else if (m_format == QFontEngine::Format_Mono) {
if (mask.depth() > 1) {
// TODO optimize this
- mask = mask.alphaChannel();
+ mask.convertTo(QImage::Format_Alpha8);
+ mask.reinterpretAsFormat(QImage::Format_Grayscale8);
mask.invertPixels();
- mask = mask.convertToFormat(QImage::Format_Mono, Qt::ThresholdDither);
+ mask.convertTo(QImage::Format_Mono, Qt::ThresholdDither);
}
int mw = qMin(mask.width(), c.w);
int mh = qMin(mask.height(), c.h);
uchar *d = m_image.bits();
- int dbpl = m_image.bytesPerLine();
+ qsizetype dbpl = m_image.bytesPerLine();
for (int y = 0; y < c.h; ++y) {
uchar *dest = d + (c.y + y) *dbpl + c.x/8;
@@ -371,7 +355,7 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
int mw = qMin(mask.width(), c.w);
int mh = qMin(mask.height(), c.h);
uchar *d = m_image.bits();
- int dbpl = m_image.bytesPerLine();
+ qsizetype dbpl = m_image.bytesPerLine();
if (mask.depth() == 1) {
for (int y = 0; y < c.h; ++y) {
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index b6fc7230a8..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 uint 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 d75b66c50b..df57d2c190 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -1,52 +1,15 @@
-/****************************************************************************
-**
-** 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"
#include "qdebug.h"
#include "qhashfunctions.h"
-#include "qmatrix.h"
#include "qregion.h"
#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>
@@ -76,22 +39,22 @@ static void nanWarning(const char *func)
ny = FY_; \
break; \
case TxTranslate: \
- nx = FX_ + affine._dx; \
- ny = FY_ + affine._dy; \
+ nx = FX_ + m_matrix[2][0]; \
+ ny = FY_ + m_matrix[2][1]; \
break; \
case TxScale: \
- nx = affine._m11 * FX_ + affine._dx; \
- ny = affine._m22 * FY_ + affine._dy; \
+ nx = m_matrix[0][0] * FX_ + m_matrix[2][0]; \
+ ny = m_matrix[1][1] * FY_ + m_matrix[2][1]; \
break; \
case TxRotate: \
case TxShear: \
case TxProject: \
- nx = affine._m11 * FX_ + affine._m21 * FY_ + affine._dx; \
- ny = affine._m12 * FX_ + affine._m22 * FY_ + affine._dy; \
+ nx = m_matrix[0][0] * FX_ + m_matrix[1][0] * FY_ + m_matrix[2][0]; \
+ ny = m_matrix[0][1] * FX_ + m_matrix[1][1] * FY_ + m_matrix[2][1]; \
if (t == TxProject) { \
- qreal w = (m_13 * FX_ + m_23 * FY_ + m_33); \
+ 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; \
} \
@@ -109,14 +72,6 @@ static void nanWarning(const char *func)
or project the coordinate system, and is typically used when
rendering graphics.
- QTransform differs from QMatrix in that it is a true 3x3 matrix,
- allowing perspective transformations. QTransform's toAffine()
- method allows casting QTransform to QMatrix. If a perspective
- transformation has been specified on the matrix, then the
- conversion will cause loss of data.
-
- QTransform is the recommended transformation class in Qt.
-
A QTransform object can be built using the setMatrix(), scale(),
rotate(), translate() and shear() functions. Alternatively, it
can be built by applying \l {QTransform#Basic Matrix
@@ -222,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:
@@ -232,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}
*/
@@ -253,6 +229,8 @@ static void nanWarning(const char *func)
*/
/*!
+ \fn QTransform::QTransform()
+
Constructs an identity matrix.
All elements are set to zero except \c m11 and \c m22 (specifying
@@ -260,16 +238,6 @@ static void nanWarning(const char *func)
\sa reset()
*/
-QTransform::QTransform()
- : affine(true)
- , m_13(0), m_23(0), m_33(1)
- , m_type(TxNone)
- , m_dirty(TxNone)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
-{
-}
/*!
\fn QTransform::QTransform(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33)
@@ -279,18 +247,6 @@ QTransform::QTransform()
\sa setMatrix()
*/
-QTransform::QTransform(qreal h11, qreal h12, qreal h13,
- qreal h21, qreal h22, qreal h23,
- qreal h31, qreal h32, qreal h33)
- : affine(h11, h12, h21, h22, h31, h32, true)
- , m_13(h13), m_23(h23), m_33(h33)
- , m_type(TxNone)
- , m_dirty(TxProject)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
-{
-}
/*!
\fn QTransform::QTransform(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
@@ -299,35 +255,6 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h13,
\sa setMatrix()
*/
-QTransform::QTransform(qreal h11, qreal h12, qreal h21,
- qreal h22, qreal dx, qreal dy)
- : affine(h11, h12, h21, h22, dx, dy, true)
- , m_13(0), m_23(0), m_33(1)
- , m_type(TxNone)
- , m_dirty(TxShear)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
-{
-}
-
-/*!
- \fn QTransform::QTransform(const QMatrix &matrix)
-
- Constructs a matrix that is a copy of the given \a matrix.
- Note that the \c m13, \c m23, and \c m33 elements are set to 0, 0,
- and 1 respectively.
- */
-QTransform::QTransform(const QMatrix &mtx)
- : affine(mtx._m11, mtx._m12, mtx._m21, mtx._m22, mtx._dx, mtx._dy, true),
- m_13(0), m_23(0), m_33(1)
- , m_type(TxNone)
- , m_dirty(TxShear)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
-{
-}
/*!
Returns the adjoint of this matrix.
@@ -335,21 +262,21 @@ QTransform::QTransform(const QMatrix &mtx)
QTransform QTransform::adjoint() const
{
qreal h11, h12, h13,
- h21, h22, h23,
- h31, h32, h33;
- h11 = affine._m22*m_33 - m_23*affine._dy;
- h21 = m_23*affine._dx - affine._m21*m_33;
- h31 = affine._m21*affine._dy - affine._m22*affine._dx;
- h12 = m_13*affine._dy - affine._m12*m_33;
- h22 = affine._m11*m_33 - m_13*affine._dx;
- h32 = affine._m12*affine._dx - affine._m11*affine._dy;
- h13 = affine._m12*m_23 - m_13*affine._m22;
- h23 = m_13*affine._m21 - affine._m11*m_23;
- h33 = affine._m11*affine._m22 - affine._m12*affine._m21;
+ h21, h22, h23,
+ h31, h32, h33;
+ h11 = m_matrix[1][1] * m_matrix[2][2] - m_matrix[1][2] * m_matrix[2][1];
+ h21 = m_matrix[1][2] * m_matrix[2][0] - m_matrix[1][0] * m_matrix[2][2];
+ h31 = m_matrix[1][0] * m_matrix[2][1] - m_matrix[1][1] * m_matrix[2][0];
+ h12 = m_matrix[0][2] * m_matrix[2][1] - m_matrix[0][1] * m_matrix[2][2];
+ h22 = m_matrix[0][0] * m_matrix[2][2] - m_matrix[0][2] * m_matrix[2][0];
+ h32 = m_matrix[0][1] * m_matrix[2][0] - m_matrix[0][0] * m_matrix[2][1];
+ h13 = m_matrix[0][1] * m_matrix[1][2] - m_matrix[0][2] * m_matrix[1][1];
+ h23 = m_matrix[0][2] * m_matrix[1][0] - m_matrix[0][0] * m_matrix[1][2];
+ h33 = m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0];
return QTransform(h11, h12, h13,
h21, h22, h23,
- h31, h32, h33, true);
+ h31, h32, h33);
}
/*!
@@ -357,9 +284,9 @@ QTransform QTransform::adjoint() const
*/
QTransform QTransform::transposed() const
{
- QTransform t(affine._m11, affine._m21, affine._dx,
- affine._m12, affine._m22, affine._dy,
- m_13, m_23, m_33, true);
+ QTransform t(m_matrix[0][0], m_matrix[1][0], m_matrix[2][0],
+ m_matrix[0][1], m_matrix[1][1], m_matrix[2][1],
+ m_matrix[0][2], m_matrix[1][2], m_matrix[2][2]);
return t;
}
@@ -375,30 +302,30 @@ QTransform QTransform::transposed() const
*/
QTransform QTransform::inverted(bool *invertible) const
{
- QTransform invert(true);
+ QTransform invert;
bool inv = true;
switch(inline_type()) {
case TxNone:
break;
case TxTranslate:
- invert.affine._dx = -affine._dx;
- invert.affine._dy = -affine._dy;
+ invert.m_matrix[2][0] = -m_matrix[2][0];
+ invert.m_matrix[2][1] = -m_matrix[2][1];
break;
case TxScale:
- inv = !qFuzzyIsNull(affine._m11);
- inv &= !qFuzzyIsNull(affine._m22);
+ inv = !qFuzzyIsNull(m_matrix[0][0]);
+ inv &= !qFuzzyIsNull(m_matrix[1][1]);
if (inv) {
- invert.affine._m11 = 1. / affine._m11;
- invert.affine._m22 = 1. / affine._m22;
- invert.affine._dx = -affine._dx * invert.affine._m11;
- invert.affine._dy = -affine._dy * invert.affine._m22;
+ invert.m_matrix[0][0] = 1. / m_matrix[0][0];
+ invert.m_matrix[1][1] = 1. / m_matrix[1][1];
+ invert.m_matrix[2][0] = -m_matrix[2][0] * invert.m_matrix[0][0];
+ invert.m_matrix[2][1] = -m_matrix[2][1] * invert.m_matrix[1][1];
}
break;
- case TxRotate:
- case TxShear:
- invert.affine = affine.inverted(&inv);
- break;
+// case TxRotate:
+// case TxShear:
+// invert.affine = affine.inverted(&inv);
+// break;
default:
// general case
qreal det = determinant();
@@ -431,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;
}
@@ -439,24 +366,24 @@ QTransform &QTransform::translate(qreal dx, qreal dy)
switch(inline_type()) {
case TxNone:
- affine._dx = dx;
- affine._dy = dy;
+ m_matrix[2][0] = dx;
+ m_matrix[2][1] = dy;
break;
case TxTranslate:
- affine._dx += dx;
- affine._dy += dy;
+ m_matrix[2][0] += dx;
+ m_matrix[2][1] += dy;
break;
case TxScale:
- affine._dx += dx*affine._m11;
- affine._dy += dy*affine._m22;
+ m_matrix[2][0] += dx * m_matrix[0][0];
+ m_matrix[2][1] += dy * m_matrix[1][1];
break;
case TxProject:
- m_33 += dx*m_13 + dy*m_23;
+ m_matrix[2][2] += dx * m_matrix[0][2] + dy * m_matrix[1][2];
Q_FALLTHROUGH();
case TxShear:
case TxRotate:
- affine._dx += dx*affine._m11 + dy*affine._m21;
- affine._dy += dy*affine._m22 + dx*affine._m12;
+ m_matrix[2][0] += dx * m_matrix[0][0] + dy * m_matrix[1][0];
+ m_matrix[2][1] += dy * m_matrix[1][1] + dx * m_matrix[0][1];
break;
}
if (m_dirty < TxTranslate)
@@ -474,12 +401,12 @@ 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();
}
#endif
- QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1, true);
+ QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1);
if (dx == 0 && dy == 0)
transform.m_type = TxNone;
else
@@ -499,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;
}
@@ -508,21 +435,21 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
switch(inline_type()) {
case TxNone:
case TxTranslate:
- affine._m11 = sx;
- affine._m22 = sy;
+ m_matrix[0][0] = sx;
+ m_matrix[1][1] = sy;
break;
case TxProject:
- m_13 *= sx;
- m_23 *= sy;
+ m_matrix[0][2] *= sx;
+ m_matrix[1][2] *= sy;
Q_FALLTHROUGH();
case TxRotate:
case TxShear:
- affine._m12 *= sx;
- affine._m21 *= sy;
+ m_matrix[0][1] *= sx;
+ m_matrix[1][0] *= sy;
Q_FALLTHROUGH();
case TxScale:
- affine._m11 *= sx;
- affine._m22 *= sy;
+ m_matrix[0][0] *= sx;
+ m_matrix[1][1] *= sy;
break;
}
if (m_dirty < TxScale)
@@ -540,12 +467,12 @@ 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();
}
#endif
- QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1, true);
+ QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1);
if (sx == 1. && sy == 1.)
transform.m_type = TxNone;
else
@@ -565,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;
}
@@ -574,28 +501,30 @@ QTransform & QTransform::shear(qreal sh, qreal sv)
switch(inline_type()) {
case TxNone:
case TxTranslate:
- affine._m12 = sv;
- affine._m21 = sh;
+ m_matrix[0][1] = sv;
+ m_matrix[1][0] = sh;
break;
case TxScale:
- affine._m12 = sv*affine._m22;
- affine._m21 = sh*affine._m11;
+ m_matrix[0][1] = sv*m_matrix[1][1];
+ m_matrix[1][0] = sh*m_matrix[0][0];
break;
case TxProject: {
- qreal tm13 = sv*m_23;
- qreal tm23 = sh*m_13;
- m_13 += tm13;
- m_23 += tm23;
+ qreal tm13 = sv * m_matrix[1][2];
+ qreal tm23 = sh * m_matrix[0][2];
+ m_matrix[0][2] += tm13;
+ m_matrix[1][2] += tm23;
}
Q_FALLTHROUGH();
case TxRotate:
case TxShear: {
- qreal tm11 = sv*affine._m21;
- qreal tm22 = sh*affine._m12;
- qreal tm12 = sv*affine._m22;
- qreal tm21 = sh*affine._m11;
- affine._m11 += tm11; affine._m12 += tm12;
- affine._m21 += tm21; affine._m22 += tm22;
+ qreal tm11 = sv * m_matrix[1][0];
+ qreal tm22 = sh * m_matrix[0][1];
+ qreal tm12 = sv * m_matrix[1][1];
+ qreal tm21 = sh * m_matrix[0][0];
+ m_matrix[0][0] += tm11;
+ m_matrix[0][1] += tm12;
+ m_matrix[1][0] += tm21;
+ m_matrix[1][1] += tm22;
break;
}
}
@@ -604,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;
}
@@ -641,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);
}
@@ -650,48 +583,55 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
switch(inline_type()) {
case TxNone:
case TxTranslate:
- affine._m11 = cosa;
- affine._m12 = sina;
- affine._m21 = -sina;
- affine._m22 = cosa;
+ m_matrix[0][0] = cosa;
+ m_matrix[0][1] = sina;
+ m_matrix[1][0] = -sina;
+ m_matrix[1][1] = cosa;
break;
case TxScale: {
- qreal tm11 = cosa*affine._m11;
- qreal tm12 = sina*affine._m22;
- qreal tm21 = -sina*affine._m11;
- qreal tm22 = cosa*affine._m22;
- affine._m11 = tm11; affine._m12 = tm12;
- affine._m21 = tm21; affine._m22 = tm22;
+ qreal tm11 = cosa * m_matrix[0][0];
+ qreal tm12 = sina * m_matrix[1][1];
+ qreal tm21 = -sina * m_matrix[0][0];
+ qreal tm22 = cosa * m_matrix[1][1];
+ m_matrix[0][0] = tm11;
+ m_matrix[0][1] = tm12;
+ m_matrix[1][0] = tm21;
+ m_matrix[1][1] = tm22;
break;
}
case TxProject: {
- qreal tm13 = cosa*m_13 + sina*m_23;
- qreal tm23 = -sina*m_13 + cosa*m_23;
- m_13 = tm13;
- m_23 = tm23;
+ qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2];
+ qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2];
+ m_matrix[0][2] = tm13;
+ m_matrix[1][2] = tm23;
Q_FALLTHROUGH();
}
case TxRotate:
case TxShear: {
- qreal tm11 = cosa*affine._m11 + sina*affine._m21;
- qreal tm12 = cosa*affine._m12 + sina*affine._m22;
- qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
- qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
- affine._m11 = tm11; affine._m12 = tm12;
- affine._m21 = tm21; affine._m22 = tm22;
+ qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0];
+ qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1];
+ qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0];
+ qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1];
+ m_matrix[0][0] = tm11;
+ m_matrix[0][1] = tm12;
+ m_matrix[1][0] = tm21;
+ m_matrix[1][1] = tm22;
break;
}
}
if (m_dirty < TxRotate)
m_dirty = TxRotate;
} else {
+ if (!qIsNull(distanceToPlane))
+ sina /= distanceToPlane;
+
QTransform result;
if (axis == Qt::YAxis) {
- result.affine._m11 = cosa;
- result.m_13 = -sina * inv_dist_to_plane;
+ result.m_matrix[0][0] = cosa;
+ result.m_matrix[0][2] = -sina;
} else {
- result.affine._m22 = cosa;
- result.m_23 = -sina * inv_dist_to_plane;
+ result.m_matrix[1][1] = cosa;
+ result.m_matrix[1][2] = -sina;
}
result.m_type = TxProject;
*this = result * *this;
@@ -700,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.
- Rotates the coordinate system counterclockwise by the given \a angle
- about the specified \a axis and returns a reference to the matrix.
+ \include qtransform.cpp transform-rotate-note
+ \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;
}
@@ -729,48 +694,55 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
switch(inline_type()) {
case TxNone:
case TxTranslate:
- affine._m11 = cosa;
- affine._m12 = sina;
- affine._m21 = -sina;
- affine._m22 = cosa;
+ m_matrix[0][0] = cosa;
+ m_matrix[0][1] = sina;
+ m_matrix[1][0] = -sina;
+ m_matrix[1][1] = cosa;
break;
case TxScale: {
- qreal tm11 = cosa*affine._m11;
- qreal tm12 = sina*affine._m22;
- qreal tm21 = -sina*affine._m11;
- qreal tm22 = cosa*affine._m22;
- affine._m11 = tm11; affine._m12 = tm12;
- affine._m21 = tm21; affine._m22 = tm22;
+ qreal tm11 = cosa * m_matrix[0][0];
+ qreal tm12 = sina * m_matrix[1][1];
+ qreal tm21 = -sina * m_matrix[0][0];
+ qreal tm22 = cosa * m_matrix[1][1];
+ m_matrix[0][0] = tm11;
+ m_matrix[0][1] = tm12;
+ m_matrix[1][0] = tm21;
+ m_matrix[1][1] = tm22;
break;
}
case TxProject: {
- qreal tm13 = cosa*m_13 + sina*m_23;
- qreal tm23 = -sina*m_13 + cosa*m_23;
- m_13 = tm13;
- m_23 = tm23;
+ qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2];
+ qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2];
+ m_matrix[0][2] = tm13;
+ m_matrix[1][2] = tm23;
Q_FALLTHROUGH();
}
case TxRotate:
case TxShear: {
- qreal tm11 = cosa*affine._m11 + sina*affine._m21;
- qreal tm12 = cosa*affine._m12 + sina*affine._m22;
- qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
- qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
- affine._m11 = tm11; affine._m12 = tm12;
- affine._m21 = tm21; affine._m22 = tm22;
+ qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0];
+ qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1];
+ qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0];
+ qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1];
+ m_matrix[0][0] = tm11;
+ m_matrix[0][1] = tm12;
+ m_matrix[1][0] = tm21;
+ m_matrix[1][1] = tm22;
break;
}
}
if (m_dirty < TxRotate)
m_dirty = TxRotate;
} else {
+ if (!qIsNull(distanceToPlane))
+ sina /= distanceToPlane;
+
QTransform result;
if (axis == Qt::YAxis) {
- result.affine._m11 = cosa;
- result.m_13 = -sina * inv_dist_to_plane;
+ result.m_matrix[0][0] = cosa;
+ result.m_matrix[0][2] = -sina;
} else {
- result.affine._m22 = cosa;
- result.m_23 = -sina * inv_dist_to_plane;
+ result.m_matrix[1][1] = cosa;
+ result.m_matrix[1][2] = -sina;
}
result.m_type = TxProject;
*this = result * *this;
@@ -778,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,
@@ -785,15 +775,15 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
*/
bool QTransform::operator==(const QTransform &o) const
{
- return affine._m11 == o.affine._m11 &&
- affine._m12 == o.affine._m12 &&
- affine._m21 == o.affine._m21 &&
- affine._m22 == o.affine._m22 &&
- affine._dx == o.affine._dx &&
- affine._dy == o.affine._dy &&
- m_13 == o.m_13 &&
- m_23 == o.m_23 &&
- m_33 == o.m_33;
+ return m_matrix[0][0] == o.m_matrix[0][0] &&
+ m_matrix[0][1] == o.m_matrix[0][1] &&
+ m_matrix[1][0] == o.m_matrix[1][0] &&
+ m_matrix[1][1] == o.m_matrix[1][1] &&
+ m_matrix[2][0] == o.m_matrix[2][0] &&
+ m_matrix[2][1] == o.m_matrix[2][1] &&
+ m_matrix[0][2] == o.m_matrix[0][2] &&
+ m_matrix[1][2] == o.m_matrix[1][2] &&
+ m_matrix[2][2] == o.m_matrix[2][2];
}
/*!
@@ -803,7 +793,7 @@ bool QTransform::operator==(const QTransform &o) const
Returns the hash value for \a key, using
\a seed to seed the calculation.
*/
-uint qHash(const QTransform &key, uint seed) noexcept
+size_t qHash(const QTransform &key, size_t seed) noexcept
{
QtPrivate::QHashCombine hash;
seed = hash(seed, key.m11());
@@ -851,56 +841,59 @@ QTransform & QTransform::operator*=(const QTransform &o)
case TxNone:
break;
case TxTranslate:
- affine._dx += o.affine._dx;
- affine._dy += o.affine._dy;
+ m_matrix[2][0] += o.m_matrix[2][0];
+ m_matrix[2][1] += o.m_matrix[2][1];
break;
case TxScale:
{
- qreal m11 = affine._m11*o.affine._m11;
- qreal m22 = affine._m22*o.affine._m22;
+ qreal m11 = m_matrix[0][0] * o.m_matrix[0][0];
+ qreal m22 = m_matrix[1][1] * o.m_matrix[1][1];
- qreal m31 = affine._dx*o.affine._m11 + o.affine._dx;
- qreal m32 = affine._dy*o.affine._m22 + o.affine._dy;
+ qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + o.m_matrix[2][0];
+ qreal m32 = m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1];
- affine._m11 = m11;
- affine._m22 = m22;
- affine._dx = m31; affine._dy = m32;
+ m_matrix[0][0] = m11;
+ m_matrix[1][1] = m22;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32;
break;
}
case TxRotate:
case TxShear:
{
- qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21;
- qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22;
+ qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0];
+ qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1];
- qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21;
- qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22;
+ qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0];
+ qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1];
- qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + o.affine._dx;
- qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + o.affine._dy;
+ qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + m_matrix[2][1] * o.m_matrix[1][0] + o.m_matrix[2][0];
+ qreal m32 = m_matrix[2][0] * o.m_matrix[0][1] + m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1];
- affine._m11 = m11; affine._m12 = m12;
- affine._m21 = m21; affine._m22 = m22;
- affine._dx = m31; affine._dy = m32;
+ m_matrix[0][0] = m11;
+ m_matrix[0][1] = m12;
+ m_matrix[1][0] = m21;
+ m_matrix[1][1] = m22;
+ m_matrix[2][0] = m31;
+ m_matrix[2][1] = m32;
break;
}
case TxProject:
{
- qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21 + m_13*o.affine._dx;
- qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22 + m_13*o.affine._dy;
- qreal m13 = affine._m11*o.m_13 + affine._m12*o.m_23 + m_13*o.m_33;
+ qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0] + m_matrix[0][2] * o.m_matrix[2][0];
+ qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1] + m_matrix[0][2] * o.m_matrix[2][1];
+ qreal m13 = m_matrix[0][0] * o.m_matrix[0][2] + m_matrix[0][1] * o.m_matrix[1][2] + m_matrix[0][2] * o.m_matrix[2][2];
- qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21 + m_23*o.affine._dx;
- qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22 + m_23*o.affine._dy;
- qreal m23 = affine._m21*o.m_13 + affine._m22*o.m_23 + m_23*o.m_33;
+ qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0] + m_matrix[1][2] * o.m_matrix[2][0];
+ qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1] + m_matrix[1][2] * o.m_matrix[2][1];
+ qreal m23 = m_matrix[1][0] * o.m_matrix[0][2] + m_matrix[1][1] * o.m_matrix[1][2] + m_matrix[1][2] * o.m_matrix[2][2];
- qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + m_33*o.affine._dx;
- qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + m_33*o.affine._dy;
- qreal m33 = affine._dx*o.m_13 + affine._dy*o.m_23 + m_33*o.m_33;
+ qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + m_matrix[2][1] * o.m_matrix[1][0] + m_matrix[2][2] * o.m_matrix[2][0];
+ qreal m32 = m_matrix[2][0] * o.m_matrix[0][1] + m_matrix[2][1] * o.m_matrix[1][1] + m_matrix[2][2] * o.m_matrix[2][1];
+ qreal m33 = m_matrix[2][0] * o.m_matrix[0][2] + m_matrix[2][1] * o.m_matrix[1][2] + m_matrix[2][2] * o.m_matrix[2][2];
- affine._m11 = m11; affine._m12 = m12; m_13 = m13;
- affine._m21 = m21; affine._m22 = m22; m_23 = m23;
- affine._dx = m31; affine._dy = m32; m_33 = m33;
+ m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
+ m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
}
}
@@ -928,62 +921,63 @@ QTransform QTransform::operator*(const QTransform &m) const
if (thisType == TxNone)
return m;
- QTransform t(true);
+ QTransform t;
TransformationType type = qMax(thisType, otherType);
switch(type) {
case TxNone:
break;
case TxTranslate:
- t.affine._dx = affine._dx + m.affine._dx;
- t.affine._dy += affine._dy + m.affine._dy;
+ t.m_matrix[2][0] = m_matrix[2][0] + m.m_matrix[2][0];
+ t.m_matrix[2][1] = m_matrix[2][1] + m.m_matrix[2][1];
break;
case TxScale:
{
- qreal m11 = affine._m11*m.affine._m11;
- qreal m22 = affine._m22*m.affine._m22;
+ qreal m11 = m_matrix[0][0] * m.m_matrix[0][0];
+ qreal m22 = m_matrix[1][1] * m.m_matrix[1][1];
- qreal m31 = affine._dx*m.affine._m11 + m.affine._dx;
- qreal m32 = affine._dy*m.affine._m22 + m.affine._dy;
+ qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m.m_matrix[2][0];
+ qreal m32 = m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1];
- t.affine._m11 = m11;
- t.affine._m22 = m22;
- t.affine._dx = m31; t.affine._dy = m32;
+ t.m_matrix[0][0] = m11;
+ t.m_matrix[1][1] = m22;
+ t.m_matrix[2][0] = m31;
+ t.m_matrix[2][1] = m32;
break;
}
case TxRotate:
case TxShear:
{
- qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21;
- qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22;
+ qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0];
+ qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1];
- qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21;
- qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22;
+ qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0];
+ qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1];
- qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m.affine._dx;
- qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m.affine._dy;
+ qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m_matrix[2][1] * m.m_matrix[1][0] + m.m_matrix[2][0];
+ qreal m32 = m_matrix[2][0] * m.m_matrix[0][1] + m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1];
- t.affine._m11 = m11; t.affine._m12 = m12;
- t.affine._m21 = m21; t.affine._m22 = m22;
- t.affine._dx = m31; t.affine._dy = m32;
+ t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12;
+ t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22;
+ t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32;
break;
}
case TxProject:
{
- qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21 + m_13*m.affine._dx;
- qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22 + m_13*m.affine._dy;
- qreal m13 = affine._m11*m.m_13 + affine._m12*m.m_23 + m_13*m.m_33;
+ qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0] + m_matrix[0][2] * m.m_matrix[2][0];
+ qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1] + m_matrix[0][2] * m.m_matrix[2][1];
+ qreal m13 = m_matrix[0][0] * m.m_matrix[0][2] + m_matrix[0][1] * m.m_matrix[1][2] + m_matrix[0][2] * m.m_matrix[2][2];
- qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21 + m_23*m.affine._dx;
- qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22 + m_23*m.affine._dy;
- qreal m23 = affine._m21*m.m_13 + affine._m22*m.m_23 + m_23*m.m_33;
+ qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0] + m_matrix[1][2] * m.m_matrix[2][0];
+ qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1] + m_matrix[1][2] * m.m_matrix[2][1];
+ qreal m23 = m_matrix[1][0] * m.m_matrix[0][2] + m_matrix[1][1] * m.m_matrix[1][2] + m_matrix[1][2] * m.m_matrix[2][2];
- qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m_33*m.affine._dx;
- qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m_33*m.affine._dy;
- qreal m33 = affine._dx*m.m_13 + affine._dy*m.m_23 + m_33*m.m_33;
+ qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m_matrix[2][1] * m.m_matrix[1][0] + m_matrix[2][2] * m.m_matrix[2][0];
+ qreal m32 = m_matrix[2][0] * m.m_matrix[0][1] + m_matrix[2][1] * m.m_matrix[1][1] + m_matrix[2][2] * m.m_matrix[2][1];
+ qreal m33 = m_matrix[2][0] * m.m_matrix[0][2] + m_matrix[2][1] * m.m_matrix[1][2] + m_matrix[2][2] * m.m_matrix[2][2];
- t.affine._m11 = m11; t.affine._m12 = m12; t.m_13 = m13;
- t.affine._m21 = m21; t.affine._m22 = m22; t.m_23 = m23;
- t.affine._dx = m31; t.affine._dy = m32; t.m_33 = m33;
+ t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12; t.m_matrix[0][2] = m13;
+ t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22; t.m_matrix[1][2] = m23;
+ t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32; t.m_matrix[2][2] = m33;
}
}
@@ -1025,27 +1019,11 @@ QTransform QTransform::operator*(const QTransform &m) const
element of this matrix.
*/
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
/*!
+ \fn QTransform &QTransform::operator=(const QTransform &matrix) noexcept
+
Assigns the given \a matrix's values to this matrix.
*/
-QTransform & QTransform::operator=(const QTransform &matrix) noexcept
-{
- affine._m11 = matrix.affine._m11;
- affine._m12 = matrix.affine._m12;
- affine._m21 = matrix.affine._m21;
- affine._m22 = matrix.affine._m22;
- affine._dx = matrix.affine._dx;
- affine._dy = matrix.affine._dy;
- m_13 = matrix.m_13;
- m_23 = matrix.m_23;
- m_33 = matrix.m_33;
- m_type = matrix.m_type;
- m_dirty = matrix.m_dirty;
-
- return *this;
-}
-#endif
/*!
Resets the matrix to an identity matrix, i.e. all elements are set
@@ -1057,10 +1035,7 @@ QTransform & QTransform::operator=(const QTransform &matrix) noexcept
*/
void QTransform::reset()
{
- affine._m11 = affine._m22 = m_33 = 1.0;
- affine._m12 = m_13 = affine._m21 = m_23 = affine._dx = affine._dy = 0;
- m_type = TxNone;
- m_dirty = TxNone;
+ *this = QTransform();
}
#ifndef QT_NO_DATASTREAM
@@ -1170,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 + affine._dx;
- y = fy + affine._dy;
- break;
- case TxScale:
- x = affine._m11 * fx + affine._dx;
- y = affine._m22 * fy + affine._dy;
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = affine._m11 * fx + affine._m21 * fy + affine._dx;
- y = affine._m12 * fx + affine._m22 * fy + affine._dy;
- if (t == TxProject) {
- qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPoint(qRound(x), qRound(y));
}
@@ -1221,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 + affine._dx;
- y = fy + affine._dy;
- break;
- case TxScale:
- x = affine._m11 * fx + affine._dx;
- y = affine._m22 * fy + affine._dy;
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = affine._m11 * fx + affine._m21 * fy + affine._dx;
- y = affine._m12 * fx + affine._m22 * fy + affine._dy;
- if (t == TxProject) {
- qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPointF(x, y);
}
@@ -1292,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 + affine._dx;
- y1 = fy1 + affine._dy;
- x2 = fx2 + affine._dx;
- y2 = fy2 + affine._dy;
- break;
- case TxScale:
- x1 = affine._m11 * fx1 + affine._dx;
- y1 = affine._m22 * fy1 + affine._dy;
- x2 = affine._m11 * fx2 + affine._dx;
- y2 = affine._m22 * fy2 + affine._dy;
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
- y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
- x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
- y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
- if (t == TxProject) {
- qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
- x1 *= w;
- y1 *= w;
- w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
- x2 *= w;
- y2 *= w;
- }
- }
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
+
return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
}
@@ -1351,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 + affine._dx;
- y1 = fy1 + affine._dy;
- x2 = fx2 + affine._dx;
- y2 = fy2 + affine._dy;
- break;
- case TxScale:
- x1 = affine._m11 * fx1 + affine._dx;
- y1 = affine._m22 * fy1 + affine._dy;
- x2 = affine._m11 * fx2 + affine._dx;
- y2 = affine._m22 * fy2 + affine._dy;
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
- y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
- x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
- y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
- if (t == TxProject) {
- qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
- x1 *= w;
- y1 *= w;
- w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
- x2 *= w;
- y2 *= w;
- }
- }
- return QLineF(x1, y1, 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);
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
- 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
@@ -1442,10 +1287,7 @@ QPolygonF QTransform::map(const QPolygonF &a) const
{
TransformationType t = inline_type();
if (t <= TxTranslate)
- return a.translated(affine._dx, affine._dy);
-
- if (t >= QTransform::TxProject)
- return mapProjective(*this, a);
+ return a.translated(m_matrix[2][0], m_matrix[2][1]);
int size = a.size();
int i;
@@ -1472,10 +1314,7 @@ QPolygon QTransform::map(const QPolygon &a) const
{
TransformationType t = inline_type();
if (t <= TxTranslate)
- return a.translated(qRound(affine._dx), qRound(affine._dy));
-
- if (t >= QTransform::TxProject)
- return mapProjective(*this, QPolygonF(a)).toPolygon();
+ return a.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
int size = a.size();
int i;
@@ -1521,7 +1360,7 @@ QRegion QTransform::map(const QRegion &r) const
if (t == TxTranslate) {
QRegion copy(r);
- copy.translate(qRound(affine._dx), qRound(affine._dy));
+ copy.translate(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
return copy;
}
@@ -1529,22 +1368,22 @@ 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;
}
QPainterPath p = map(qt_regionToPath(r));
- return p.toFillPolygon(QTransform()).toPolygon();
+ return p.toFillPolygon().toPolygon();
}
struct QHomogeneousCoordinate
@@ -1700,7 +1539,7 @@ QPainterPath QTransform::map(const QPainterPath &path) const
QPainterPath copy = path;
if (t == TxTranslate) {
- copy.translate(affine._dx, affine._dy);
+ copy.translate(m_matrix[2][0], m_matrix[2][1]);
} else {
copy.detach();
// Full xform
@@ -1740,10 +1579,10 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const
QPolygon a(4);
qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
if (t <= TxScale) {
- x[0] = affine._m11*rect.x() + affine._dx;
- y[0] = affine._m22*rect.y() + affine._dy;
- qreal w = affine._m11*rect.width();
- qreal h = affine._m22*rect.height();
+ x[0] = m_matrix[0][0]*rect.x() + m_matrix[2][0];
+ y[0] = m_matrix[1][1]*rect.y() + m_matrix[2][1];
+ qreal w = m_matrix[0][0]*rect.width();
+ qreal h = m_matrix[1][1]*rect.height();
if (w < 0) {
w = -w;
x[0] -= w;
@@ -1767,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]),
@@ -1785,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();
@@ -1900,32 +1739,24 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
qreal m21, qreal m22, qreal m23,
qreal m31, qreal m32, qreal m33)
{
- affine._m11 = m11; affine._m12 = m12; m_13 = m13;
- affine._m21 = m21; affine._m22 = m22; m_23 = m23;
- affine._dx = m31; affine._dy = m32; m_33 = m33;
+ m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
+ m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
+ m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
m_type = TxNone;
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();
if (t <= TxTranslate)
- return rect.translated(qRound(affine._dx), qRound(affine._dy));
+ return rect.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
if (t <= TxScale) {
- int x = qRound(affine._m11*rect.x() + affine._dx);
- int y = qRound(affine._m22*rect.y() + affine._dy);
- int w = qRound(affine._m11*rect.width());
- int h = qRound(affine._m22*rect.height());
+ int x = qRound(m_matrix[0][0] * rect.x() + m_matrix[2][0]);
+ int y = qRound(m_matrix[1][1] * rect.y() + m_matrix[2][1]);
+ int w = qRound(m_matrix[0][0] * rect.width());
+ int h = qRound(m_matrix[1][1] * rect.height());
if (w < 0) {
w = -w;
x -= w;
@@ -1935,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;
@@ -1958,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();
}
}
@@ -1989,13 +1815,13 @@ QRectF QTransform::mapRect(const QRectF &rect) const
{
TransformationType t = inline_type();
if (t <= TxTranslate)
- return rect.translated(affine._dx, affine._dy);
+ return rect.translated(m_matrix[2][0], m_matrix[2][1]);
if (t <= TxScale) {
- qreal x = affine._m11*rect.x() + affine._dx;
- qreal y = affine._m22*rect.y() + affine._dy;
- qreal w = affine._m11*rect.width();
- qreal h = affine._m22*rect.height();
+ qreal x = m_matrix[0][0] * rect.x() + m_matrix[2][0];
+ qreal y = m_matrix[1][1] * rect.y() + m_matrix[2][1];
+ qreal w = m_matrix[0][0] * rect.width();
+ qreal h = m_matrix[1][1] * rect.height();
if (w < 0) {
w = -w;
x -= w;
@@ -2005,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;
@@ -2028,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();
}
}
@@ -2083,17 +1905,6 @@ void QTransform::map(int x, int y, int *tx, int *ty) const
}
/*!
- Returns the QTransform as an affine matrix.
-
- \warning If a perspective transformation has been specified,
- then the conversion will cause loss of data.
-*/
-const QMatrix &QTransform::toAffine() const
-{
- return affine;
-}
-
-/*!
Returns the transformation type of this matrix.
The transformation type is the highest enumeration value
@@ -2107,20 +1918,20 @@ const QMatrix &QTransform::toAffine() 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)) {
case TxProject:
- if (!qFuzzyIsNull(m_13) || !qFuzzyIsNull(m_23) || !qFuzzyIsNull(m_33 - 1)) {
+ if (!qFuzzyIsNull(m_matrix[0][2]) || !qFuzzyIsNull(m_matrix[1][2]) || !qFuzzyIsNull(m_matrix[2][2] - 1)) {
m_type = TxProject;
break;
}
Q_FALLTHROUGH();
case TxShear:
case TxRotate:
- if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) {
- const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22;
+ if (!qFuzzyIsNull(m_matrix[0][1]) || !qFuzzyIsNull(m_matrix[1][0])) {
+ 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
@@ -2129,13 +1940,13 @@ QTransform::TransformationType QTransform::type() const
}
Q_FALLTHROUGH();
case TxScale:
- if (!qFuzzyIsNull(affine._m11 - 1) || !qFuzzyIsNull(affine._m22 - 1)) {
+ if (!qFuzzyIsNull(m_matrix[0][0] - 1) || !qFuzzyIsNull(m_matrix[1][1] - 1)) {
m_type = TxScale;
break;
}
Q_FALLTHROUGH();
case TxTranslate:
- if (!qFuzzyIsNull(affine._dx) || !qFuzzyIsNull(affine._dy)) {
+ if (!qFuzzyIsNull(m_matrix[2][0]) || !qFuzzyIsNull(m_matrix[2][1])) {
m_type = TxTranslate;
break;
}
@@ -2155,7 +1966,7 @@ QTransform::TransformationType QTransform::type() const
*/
QTransform::operator QVariant() const
{
- return QVariant(QVariant::Transform, this);
+ return QVariant::fromValue(*this);
}
@@ -2167,15 +1978,6 @@ QTransform::operator QVariant() const
\sa inverted()
*/
-#if QT_DEPRECATED_SINCE(5, 13)
-/*!
- \fn qreal QTransform::det() const
- \obsolete
-
- Returns the matrix's determinant. Use determinant() instead.
-*/
-#endif
-
/*!
\fn qreal QTransform::m11() const
@@ -2384,4 +2186,50 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
}
}
+QDataStream & operator>>(QDataStream &s, QTransform::Affine &m)
+{
+ if (s.version() == 1) {
+ float m11, m12, m21, m22, dx, dy;
+ s >> m11; s >> m12; s >> m21; s >> m22; s >> dx; s >> dy;
+
+ m.m_matrix[0][0] = m11;
+ m.m_matrix[0][1] = m12;
+ m.m_matrix[1][0] = m21;
+ m.m_matrix[1][1] = m22;
+ m.m_matrix[2][0] = dx;
+ m.m_matrix[2][1] = dy;
+ } else {
+ s >> m.m_matrix[0][0];
+ s >> m.m_matrix[0][1];
+ s >> m.m_matrix[1][0];
+ s >> m.m_matrix[1][1];
+ s >> m.m_matrix[2][0];
+ s >> m.m_matrix[2][1];
+ }
+ m.m_matrix[0][2] = 0;
+ m.m_matrix[1][2] = 0;
+ m.m_matrix[2][2] = 1;
+ return s;
+}
+
+QDataStream &operator<<(QDataStream &s, const QTransform::Affine &m)
+{
+ if (s.version() == 1) {
+ s << (float)m.m_matrix[0][0]
+ << (float)m.m_matrix[0][1]
+ << (float)m.m_matrix[1][0]
+ << (float)m.m_matrix[1][1]
+ << (float)m.m_matrix[2][0]
+ << (float)m.m_matrix[2][1];
+ } else {
+ s << m.m_matrix[0][0]
+ << m.m_matrix[0][1]
+ << m.m_matrix[1][0]
+ << m.m_matrix[1][1]
+ << m.m_matrix[2][0]
+ << m.m_matrix[2][1];
+ }
+ return s;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h
index b2a634dd2a..e5b245d8c9 100644
--- a/src/gui/painting/qtransform.h
+++ b/src/gui/painting/qtransform.h
@@ -1,47 +1,9 @@
-/****************************************************************************
-**
-** 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
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qmatrix.h>
-#include <QtGui/qpainterpath.h>
#include <QtGui/qpolygon.h>
#include <QtGui/qregion.h>
#include <QtGui/qwindowdefs.h>
@@ -51,8 +13,8 @@
QT_BEGIN_NAMESPACE
-
class QVariant;
+class QPainterPath;
class Q_GUI_EXPORT QTransform
{
@@ -66,27 +28,27 @@ public:
TxProject = 0x10
};
- inline explicit QTransform(Qt::Initialization) : affine(Qt::Uninitialized) {}
- QTransform();
+ inline explicit QTransform(Qt::Initialization) {}
+ inline QTransform()
+ : m_matrix{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }
+ , m_type(TxNone)
+ , m_dirty(TxNone) {}
QTransform(qreal h11, qreal h12, qreal h13,
qreal h21, qreal h22, qreal h23,
- qreal h31, qreal h32, qreal h33 = 1.0);
+ qreal h31, qreal h32, qreal h33)
+ : m_matrix{ {h11, h12, h13}, {h21, h22, h23}, {h31, h32, h33} }
+ , m_type(TxNone)
+ , m_dirty(TxProject) {}
QTransform(qreal h11, qreal h12, qreal h21,
- qreal h22, qreal dx, qreal dy);
- explicit QTransform(const QMatrix &mtx);
-
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- // ### Qt 6: remove; the compiler-generated ones are fine!
- QTransform &operator=(QTransform &&other) noexcept // = default
- { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QTransform)); return *this; }
- QTransform &operator=(const QTransform &) noexcept; // = default
- QTransform(QTransform &&other) noexcept // = default
- : affine(Qt::Uninitialized)
- { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(QTransform)); }
- QTransform(const QTransform &other) noexcept // = default
- : affine(Qt::Uninitialized)
- { memcpy(static_cast<void *>(this), static_cast<const void *>(&other), sizeof(QTransform)); }
-#endif
+ qreal h22, qreal dx, qreal dy)
+ : m_matrix{ {h11, h12, 0}, {h21, h22, 0}, {dx, dy, 1} }
+ , m_type(TxNone)
+ , m_dirty(TxShear) {}
+
+ QTransform &operator=(QTransform &&other) noexcept = default;
+ QTransform &operator=(const QTransform &) noexcept = default;
+ QTransform(QTransform &&other) noexcept = default;
+ QTransform(const QTransform &other) noexcept = default;
bool isAffine() const;
bool isIdentity() const;
@@ -98,10 +60,6 @@ public:
TransformationType type() const;
inline qreal determinant() const;
-#if QT_DEPRECATED_SINCE(5, 13)
- QT_DEPRECATED_X("Use determinant() instead")
- qreal det() const;
-#endif
qreal m11() const;
qreal m12() const;
@@ -119,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);
@@ -158,8 +125,6 @@ public:
void map(int x, int y, int *tx, int *ty) const;
void map(qreal x, qreal y, qreal *tx, qreal *ty) const;
- const QMatrix &toAffine() const;
-
QTransform &operator*=(qreal div);
QTransform &operator/=(qreal div);
QTransform &operator+=(qreal div);
@@ -169,44 +134,25 @@ public:
static QTransform fromScale(qreal dx, qreal dy);
private:
- inline QTransform(qreal h11, qreal h12, qreal h13,
- qreal h21, qreal h22, qreal h23,
- qreal h31, qreal h32, qreal h33, bool)
- : affine(h11, h12, h21, h22, h31, h32, true)
- , m_13(h13), m_23(h23), m_33(h33)
- , m_type(TxNone)
- , m_dirty(TxProject)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
- {
- }
- inline QTransform(bool)
- : affine(true)
- , m_13(0), m_23(0), m_33(1)
- , m_type(TxNone)
- , m_dirty(TxNone)
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- , d(nullptr)
-#endif
- {
- }
+ struct Affine {
+ qreal (& m_matrix)[3][3];
+ };
+
+public:
+ auto asAffineMatrix() { return Affine { m_matrix }; }
+ friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &s, Affine &m);
+ friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &s, const Affine &m);
+
+private:
inline TransformationType inline_type() const;
- QMatrix affine;
- qreal m_13;
- qreal m_23;
- qreal m_33;
+ qreal m_matrix[3][3];
mutable uint m_type : 5;
mutable uint m_dirty : 5;
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
- class Private;
- Private *d;
-#endif
};
-Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QTransform, Q_RELOCATABLE_TYPE);
-Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QTransform &key, uint seed = 0) noexcept;
+Q_GUI_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(const QTransform &key, size_t seed = 0) noexcept;
/******* inlines *****/
inline QTransform::TransformationType QTransform::inline_type() const
@@ -246,78 +192,71 @@ inline bool QTransform::isTranslating() const
inline qreal QTransform::determinant() const
{
- return affine._m11*(m_33*affine._m22-affine._dy*m_23) -
- affine._m21*(m_33*affine._m12-affine._dy*m_13)+affine._dx*(m_23*affine._m12-affine._m22*m_13);
-}
-#if QT_DEPRECATED_SINCE(5, 13)
-inline qreal QTransform::det() const
-{
- return determinant();
+ return m_matrix[0][0] * (m_matrix[2][2] * m_matrix[1][1] - m_matrix[2][1] * m_matrix[1][2]) -
+ m_matrix[1][0] * (m_matrix[2][2] * m_matrix[0][1] - m_matrix[2][1] * m_matrix[0][2]) +
+ m_matrix[2][0] * (m_matrix[1][2] * m_matrix[0][1] - m_matrix[1][1] * m_matrix[0][2]);
}
-#endif
inline qreal QTransform::m11() const
{
- return affine._m11;
+ return m_matrix[0][0];
}
inline qreal QTransform::m12() const
{
- return affine._m12;
+ return m_matrix[0][1];
}
inline qreal QTransform::m13() const
{
- return m_13;
+ return m_matrix[0][2];
}
inline qreal QTransform::m21() const
{
- return affine._m21;
+ return m_matrix[1][0];
}
inline qreal QTransform::m22() const
{
- return affine._m22;
+ return m_matrix[1][1];
}
inline qreal QTransform::m23() const
{
- return m_23;
+ return m_matrix[1][2];
}
inline qreal QTransform::m31() const
{
- return affine._dx;
+ return m_matrix[2][0];
}
inline qreal QTransform::m32() const
{
- return affine._dy;
+ return m_matrix[2][1];
}
inline qreal QTransform::m33() const
{
- return m_33;
+ return m_matrix[2][2];
}
inline qreal QTransform::dx() const
{
- return affine._dx;
+ return m_matrix[2][0];
}
inline qreal QTransform::dy() const
{
- return affine._dy;
+ return m_matrix[2][1];
}
QT_WARNING_PUSH
-QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
-QT_WARNING_DISABLE_GCC("-Wfloat-equal")
-QT_WARNING_DISABLE_INTEL(1572)
+QT_WARNING_DISABLE_FLOAT_COMPARE
inline QTransform &QTransform::operator*=(qreal num)
{
if (num == 1.)
return *this;
- affine._m11 *= num;
- affine._m12 *= num;
- m_13 *= num;
- affine._m21 *= num;
- affine._m22 *= num;
- m_23 *= num;
- affine._dx *= num;
- affine._dy *= num;
- m_33 *= num;
+ m_matrix[0][0] *= num;
+ m_matrix[0][1] *= num;
+ m_matrix[0][2] *= num;
+ m_matrix[1][0] *= num;
+ m_matrix[1][1] *= num;
+ m_matrix[1][2] *= num;
+ m_matrix[2][0] *= num;
+ m_matrix[2][1] *= num;
+ m_matrix[2][2] *= num;
if (m_dirty < TxScale)
m_dirty = TxScale;
return *this;
@@ -333,15 +272,15 @@ inline QTransform &QTransform::operator+=(qreal num)
{
if (num == 0)
return *this;
- affine._m11 += num;
- affine._m12 += num;
- m_13 += num;
- affine._m21 += num;
- affine._m22 += num;
- m_23 += num;
- affine._dx += num;
- affine._dy += num;
- m_33 += num;
+ m_matrix[0][0] += num;
+ m_matrix[0][1] += num;
+ m_matrix[0][2] += num;
+ m_matrix[1][0] += num;
+ m_matrix[1][1] += num;
+ m_matrix[1][2] += num;
+ m_matrix[2][0] += num;
+ m_matrix[2][1] += num;
+ m_matrix[2][2] += num;
m_dirty = TxProject;
return *this;
}
@@ -349,15 +288,15 @@ inline QTransform &QTransform::operator-=(qreal num)
{
if (num == 0)
return *this;
- affine._m11 -= num;
- affine._m12 -= num;
- m_13 -= num;
- affine._m21 -= num;
- affine._m22 -= num;
- m_23 -= num;
- affine._dx -= num;
- affine._dy -= num;
- m_33 -= num;
+ m_matrix[0][0] -= num;
+ m_matrix[0][1] -= num;
+ m_matrix[0][2] -= num;
+ m_matrix[1][0] -= num;
+ m_matrix[1][1] -= num;
+ m_matrix[1][2] -= num;
+ m_matrix[2][0] -= num;
+ m_matrix[2][1] -= num;
+ m_matrix[2][2] -= num;
m_dirty = TxProject;
return *this;
}
@@ -404,8 +343,6 @@ inline QPolygonF operator *(const QPolygonF &a, const QTransform &m)
{ return m.map(a); }
inline QRegion operator *(const QRegion &r, const QTransform &m)
{ return m.map(r); }
-inline QPainterPath operator *(const QPainterPath &p, const QTransform &m)
-{ return m.map(p); }
inline QTransform operator *(const QTransform &a, qreal n)
{ QTransform t(a); t *= n; return t; }
diff --git a/src/gui/painting/qtriangulatingstroker.cpp b/src/gui/painting/qtriangulatingstroker.cpp
index 8e0308f268..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
@@ -188,6 +153,31 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, co
while (pts < endPts) {
switch (*types) {
case QPainterPath::MoveToElement: {
+ int end = (endPts - pts) / 2;
+ int nextMoveElement = 1;
+ bool hasValidLineSegments = false;
+ while (nextMoveElement < end && types[nextMoveElement] != QPainterPath::MoveToElement) {
+ if (!hasValidLineSegments) {
+ hasValidLineSegments =
+ float(pts[0]) != float(pts[nextMoveElement * 2]) ||
+ float(pts[1]) != float(pts[nextMoveElement * 2 + 1]);
+ }
+ ++nextMoveElement;
+ }
+
+ /**
+ * 'LineToElement' may be skipped if it doesn't move the center point
+ * of the line. We should make sure that we don't end up with a lost
+ * 'MoveToElement' in the vertex buffer, not connected to anything. Since
+ * the buffer uses degenerate triangles trick to split the primitives,
+ * this spurious MoveToElement will create artifacts when rendering.
+ */
+ if (!hasValidLineSegments) {
+ pts += 2 * nextMoveElement;
+ types += nextMoveElement;
+ continue;
+ }
+
if (previousType != QPainterPath::MoveToElement)
endCapOrJoinClosed(startPts, previousPts, path.hasImplicitClose(), endsAtStart);
@@ -196,13 +186,8 @@ void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, co
if (startPts + 2 >= endPts)
return; // Nothing to see here...
- int end = (endPts - pts) / 2;
- int i = 2; // Start looking to ahead since we never have two moveto's in a row
- while (i<end && types[i] != QPainterPath::MoveToElement) {
- ++i;
- }
- endsAtStart = float(startPts[0]) == float(pts[i*2 - 2])
- && float(startPts[1]) == float(pts[i*2 - 1]);
+ endsAtStart = float(startPts[0]) == float(pts[nextMoveElement * 2 - 2])
+ && float(startPts[1]) == float(pts[nextMoveElement * 2 - 1]);
if (endsAtStart || path.hasImplicitClose())
m_cap_style = Qt::FlatCap;
@@ -517,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();
@@ -619,4 +604,3 @@ void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, c
}
QT_END_NAMESPACE
-
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 ec3ab8ff8f..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);
}
@@ -1985,7 +1952,7 @@ void QTriangulator<T>::SimpleToMonotone::createDiagonal(int lower, int upper)
int prevLower = m_edges.at(lower).previous;
int prevUpper = m_edges.at(upper).previous;
- Edge e;
+ Edge e = {};
e.twin = m_edges.size() + 1;
e.next = upper;
@@ -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 177e5e66ed..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
@@ -52,8 +16,8 @@
//
#include <QtGui/private/qtguiglobal_p.h>
-#include <QtCore/qvector.h>
#include <QtGui/private/qvectorpath_p.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -67,13 +31,13 @@ public:
inline Type type() const { return t; }
- inline void setDataUint(const QVector<quint32> &data)
+ inline void setDataUint(const QList<quint32> &data)
{
t = UnsignedInt;
indices32 = data;
}
- inline void setDataUshort(const QVector<quint16> &data)
+ inline void setDataUshort(const QList<quint16> &data)
{
t = UnsignedShort;
indices16 = data;
@@ -96,20 +60,20 @@ public:
private:
Type t;
- QVector<quint32> indices32;
- QVector<quint16> indices16;
+ QList<quint32> indices32;
+ QList<quint16> indices16;
};
struct QTriangleSet
{
// 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], ...]
+ QList<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
};
struct QPolylineSet
{
- QVector<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
+ QList<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
QVertexIndexVector indices; // End of polyline is marked with -1.
};
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.binaryjson b/src/gui/painting/webgradients.binaryjson
deleted file mode 100644
index 75edd487be..0000000000
--- a/src/gui/painting/webgradients.binaryjson
+++ /dev/null
Binary files differ
diff --git a/src/gui/painting/webgradients.cpp b/src/gui/painting/webgradients.cpp
new file mode 100644
index 0000000000..fd5031349e
--- /dev/null
+++ b/src/gui/painting/webgradients.cpp
@@ -0,0 +1,533 @@
+// 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 QList<QGradientStop> qt_preset_gradient_stops(QGradient::Preset preset)
+{
+ Q_ASSERT(preset < QGradient::NumPresets);
+ switch (preset) {
+ case QGradient::WarmFlame:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 154, 158, 255)), QGradientStop(0.99, QColor(250, 208, 196, 255)), QGradientStop(1, QColor(250, 208, 196, 255)));
+ case QGradient::NightFade:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(161, 140, 209, 255)), QGradientStop(1, QColor(251, 194, 235, 255)));
+ case QGradient::SpringWarmth:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(250, 208, 196, 255)), QGradientStop(0.01, QColor(250, 208, 196, 255)), QGradientStop(1, QColor(255, 209, 255, 255)));
+ case QGradient::JuicyPeach:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 236, 210, 255)), QGradientStop(1, QColor(252, 182, 159, 255)));
+ case QGradient::YoungPassion:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 129, 119, 255)), QGradientStop(0, QColor(255, 134, 122, 255)), QGradientStop(0.21, QColor(255, 140, 127, 255)), QGradientStop(0.52, QColor(249, 145, 133, 255)), QGradientStop(0.78, QColor(207, 85, 108, 255)), QGradientStop(1, QColor(177, 42, 91, 255)));
+ case QGradient::LadyLips:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 154, 158, 255)), QGradientStop(0.99, QColor(254, 207, 239, 255)), QGradientStop(1, QColor(254, 207, 239, 255)));
+ case QGradient::SunnyMorning:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(246, 211, 101, 255)), QGradientStop(1, QColor(253, 160, 133, 255)));
+ case QGradient::RainyAshville:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(251, 194, 235, 255)), QGradientStop(1, QColor(166, 193, 238, 255)));
+ case QGradient::FrozenDreams:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(253, 203, 241, 255)), QGradientStop(0.01, QColor(253, 203, 241, 255)), QGradientStop(1, QColor(230, 222, 233, 255)));
+ case QGradient::WinterNeva:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(161, 196, 253, 255)), QGradientStop(1, QColor(194, 233, 251, 255)));
+ case QGradient::DustyGrass:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(212, 252, 121, 255)), QGradientStop(1, QColor(150, 230, 161, 255)));
+ case QGradient::TemptingAzure:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(132, 250, 176, 255)), QGradientStop(1, QColor(143, 211, 244, 255)));
+ case QGradient::HeavyRain:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(207, 217, 223, 255)), QGradientStop(1, QColor(226, 235, 240, 255)));
+ case QGradient::AmyCrisp:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(166, 192, 254, 255)), QGradientStop(1, QColor(246, 128, 132, 255)));
+ case QGradient::MeanFruit:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(252, 203, 144, 255)), QGradientStop(1, QColor(213, 126, 235, 255)));
+ case QGradient::DeepBlue:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(224, 195, 252, 255)), QGradientStop(1, QColor(142, 197, 252, 255)));
+ case QGradient::RipeMalinka:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(240, 147, 251, 255)), QGradientStop(1, QColor(245, 87, 108, 255)));
+ case QGradient::CloudyKnoxville:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(253, 251, 251, 255)), QGradientStop(1, QColor(235, 237, 238, 255)));
+ case QGradient::MalibuBeach:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(79, 172, 254, 255)), QGradientStop(1, QColor(0, 242, 254, 255)));
+ case QGradient::NewLife:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(67, 233, 123, 255)), QGradientStop(1, QColor(56, 249, 215, 255)));
+ case QGradient::TrueSunset:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(250, 112, 154, 255)), QGradientStop(1, QColor(254, 225, 64, 255)));
+ case QGradient::MorpheusDen:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(48, 207, 208, 255)), QGradientStop(1, QColor(51, 8, 103, 255)));
+ case QGradient::RareWind:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(168, 237, 234, 255)), QGradientStop(1, QColor(254, 214, 227, 255)));
+ case QGradient::NearMoon:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(94, 231, 223, 255)), QGradientStop(1, QColor(180, 144, 202, 255)));
+ case QGradient::WildApple:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(210, 153, 194, 255)), QGradientStop(1, QColor(254, 249, 215, 255)));
+ case QGradient::SaintPetersburg:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(245, 247, 250, 255)), QGradientStop(1, QColor(195, 207, 226, 255)));
+ case QGradient::PlumPlate:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(102, 126, 234, 255)), QGradientStop(1, QColor(118, 75, 162, 255)));
+ case QGradient::EverlastingSky:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(253, 252, 251, 255)), QGradientStop(1, QColor(226, 209, 195, 255)));
+ case QGradient::HappyFisher:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(137, 247, 254, 255)), QGradientStop(1, QColor(102, 166, 255, 255)));
+ case QGradient::Blessing:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(253, 219, 146, 255)), QGradientStop(1, QColor(209, 253, 255, 255)));
+ case QGradient::SharpeyeEagle:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(152, 144, 227, 255)), QGradientStop(1, QColor(177, 244, 207, 255)));
+ case QGradient::LadogaBottom:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(235, 192, 253, 255)), QGradientStop(1, QColor(217, 222, 216, 255)));
+ case QGradient::LemonGate:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(150, 251, 196, 255)), QGradientStop(1, QColor(249, 245, 134, 255)));
+ case QGradient::ItmeoBranding:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(42, 245, 152, 255)), QGradientStop(1, QColor(0, 158, 253, 255)));
+ case QGradient::ZeusMiracle:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(205, 156, 242, 255)), QGradientStop(1, QColor(246, 243, 255, 255)));
+ case QGradient::OldHat:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(228, 175, 203, 255)), QGradientStop(0, QColor(184, 203, 184, 255)), QGradientStop(0, QColor(184, 203, 184, 255)), QGradientStop(0.3, QColor(226, 197, 139, 255)), QGradientStop(0.64, QColor(194, 206, 156, 255)), QGradientStop(1, QColor(126, 219, 220, 255)));
+ case QGradient::StarWine:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(184, 203, 184, 255)), QGradientStop(0, QColor(184, 203, 184, 255)), QGradientStop(0, QColor(180, 101, 218, 255)), QGradientStop(0.33, QColor(207, 108, 201, 255)), QGradientStop(0.66, QColor(238, 96, 156, 255)), QGradientStop(1, QColor(238, 96, 156, 255)));
+ case QGradient::HappyAcid:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(55, 236, 186, 255)), QGradientStop(1, QColor(114, 175, 211, 255)));
+ case QGradient::AwesomePine:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(235, 187, 167, 255)), QGradientStop(1, QColor(207, 199, 248, 255)));
+ case QGradient::NewYork:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 241, 235, 255)), QGradientStop(1, QColor(172, 224, 249, 255)));
+ case QGradient::ShyRainbow:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(238, 162, 162, 255)), QGradientStop(0.19, QColor(187, 193, 191, 255)), QGradientStop(0.42, QColor(87, 198, 225, 255)), QGradientStop(0.79, QColor(180, 159, 218, 255)), QGradientStop(1, QColor(122, 197, 216, 255)));
+ case QGradient::MixedHopes:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(196, 113, 245, 255)), QGradientStop(1, QColor(250, 113, 205, 255)));
+ case QGradient::FlyHigh:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(72, 198, 239, 255)), QGradientStop(1, QColor(111, 134, 214, 255)));
+ case QGradient::StrongBliss:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(247, 140, 160, 255)), QGradientStop(0.19, QColor(249, 116, 143, 255)), QGradientStop(0.6, QColor(253, 134, 140, 255)), QGradientStop(1, QColor(254, 154, 139, 255)));
+ case QGradient::FreshMilk:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(254, 173, 166, 255)), QGradientStop(1, QColor(245, 239, 239, 255)));
+ case QGradient::SnowAgain:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(230, 233, 240, 255)), QGradientStop(1, QColor(238, 241, 245, 255)));
+ case QGradient::FebruaryInk:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(172, 203, 238, 255)), QGradientStop(1, QColor(231, 240, 253, 255)));
+ case QGradient::KindSteel:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(233, 222, 250, 255)), QGradientStop(1, QColor(251, 252, 219, 255)));
+ case QGradient::SoftGrass:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(193, 223, 196, 255)), QGradientStop(1, QColor(222, 236, 221, 255)));
+ case QGradient::GrownEarly:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(11, 163, 96, 255)), QGradientStop(1, QColor(60, 186, 146, 255)));
+ case QGradient::SharpBlues:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(0, 198, 251, 255)), QGradientStop(1, QColor(0, 91, 234, 255)));
+ case QGradient::ShadyWater:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(116, 235, 213, 255)), QGradientStop(1, QColor(159, 172, 230, 255)));
+ case QGradient::DirtyBeauty:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(106, 133, 182, 255)), QGradientStop(1, QColor(186, 200, 224, 255)));
+ case QGradient::GreatWhale:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(163, 189, 237, 255)), QGradientStop(1, QColor(105, 145, 199, 255)));
+ case QGradient::TeenNotebook:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(151, 149, 240, 255)), QGradientStop(1, QColor(251, 200, 212, 255)));
+ case QGradient::PoliteRumors:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(167, 166, 203, 255)), QGradientStop(0.52, QColor(137, 137, 186, 255)), QGradientStop(1, QColor(137, 137, 186, 255)));
+ case QGradient::SweetPeriod:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(63, 81, 177, 255)), QGradientStop(0.13, QColor(90, 85, 174, 255)), QGradientStop(0.25, QColor(123, 95, 172, 255)), QGradientStop(0.38, QColor(143, 106, 174, 255)), QGradientStop(0.5, QColor(168, 106, 164, 255)), QGradientStop(0.62, QColor(204, 107, 142, 255)), QGradientStop(0.75, QColor(241, 130, 113, 255)), QGradientStop(0.87, QColor(243, 164, 105, 255)), QGradientStop(1, QColor(247, 201, 120, 255)));
+ case QGradient::WideMatrix:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(252, 197, 228, 255)), QGradientStop(0.15, QColor(253, 163, 75, 255)), QGradientStop(0.35, QColor(255, 120, 130, 255)), QGradientStop(0.52, QColor(200, 105, 158, 255)), QGradientStop(0.71, QColor(112, 70, 170, 255)), QGradientStop(0.87, QColor(12, 29, 184, 255)), QGradientStop(1, QColor(2, 15, 117, 255)));
+ case QGradient::SoftCherish:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(219, 220, 215, 255)), QGradientStop(0.24, QColor(221, 220, 215, 255)), QGradientStop(0.3, QColor(226, 201, 204, 255)), QGradientStop(0.46, QColor(231, 98, 125, 255)), QGradientStop(0.59, QColor(184, 35, 90, 255)), QGradientStop(0.71, QColor(128, 19, 87, 255)), QGradientStop(0.84, QColor(61, 22, 53, 255)), QGradientStop(1, QColor(28, 26, 39, 255)));
+ case QGradient::RedSalvation:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(244, 59, 71, 255)), QGradientStop(1, QColor(69, 58, 148, 255)));
+ case QGradient::BurningSpring:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(79, 181, 118, 255)), QGradientStop(0.3, QColor(68, 196, 137, 255)), QGradientStop(0.46, QColor(40, 169, 174, 255)), QGradientStop(0.59, QColor(40, 162, 183, 255)), QGradientStop(0.71, QColor(76, 119, 136, 255)), QGradientStop(0.86, QColor(108, 79, 99, 255)), QGradientStop(1, QColor(67, 44, 57, 255)));
+ case QGradient::NightParty:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(2, 80, 197, 255)), QGradientStop(1, QColor(212, 63, 141, 255)));
+ case QGradient::SkyGlider:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(136, 211, 206, 255)), QGradientStop(1, QColor(110, 69, 226, 255)));
+ case QGradient::HeavenPeach:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(217, 175, 217, 255)), QGradientStop(1, QColor(151, 217, 225, 255)));
+ case QGradient::PurpleDivision:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(112, 40, 228, 255)), QGradientStop(1, QColor(229, 178, 202, 255)));
+ case QGradient::AquaSplash:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(19, 84, 122, 255)), QGradientStop(1, QColor(128, 208, 199, 255)));
+ case QGradient::SpikyNaga:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(80, 82, 133, 255)), QGradientStop(0.12, QColor(88, 94, 146, 255)), QGradientStop(0.25, QColor(101, 104, 159, 255)), QGradientStop(0.37, QColor(116, 116, 176, 255)), QGradientStop(0.5, QColor(126, 126, 187, 255)), QGradientStop(0.62, QColor(131, 137, 199, 255)), QGradientStop(0.75, QColor(151, 149, 212, 255)), QGradientStop(0.87, QColor(162, 161, 220, 255)), QGradientStop(1, QColor(181, 174, 228, 255)));
+ case QGradient::LoveKiss:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 8, 68, 255)), QGradientStop(1, QColor(255, 177, 153, 255)));
+ case QGradient::CleanMirror:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(147, 165, 207, 255)), QGradientStop(1, QColor(228, 239, 233, 255)));
+ case QGradient::PremiumDark:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(67, 67, 67, 255)), QGradientStop(1, QColor(0, 0, 0, 255)));
+ case QGradient::ColdEvening:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(12, 52, 131, 255)), QGradientStop(1, QColor(162, 182, 223, 255)), QGradientStop(1, QColor(107, 140, 206, 255)), QGradientStop(1, QColor(162, 182, 223, 255)));
+ case QGradient::CochitiLake:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(147, 165, 207, 255)), QGradientStop(1, QColor(228, 239, 233, 255)));
+ case QGradient::SummerGames:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(146, 254, 157, 255)), QGradientStop(1, QColor(0, 201, 255, 255)));
+ case QGradient::PassionateBed:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 117, 140, 255)), QGradientStop(1, QColor(255, 126, 179, 255)));
+ case QGradient::MountainRock:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(134, 143, 150, 255)), QGradientStop(1, QColor(89, 97, 100, 255)));
+ case QGradient::DesertHump:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(199, 144, 129, 255)), QGradientStop(1, QColor(223, 165, 121, 255)));
+ case QGradient::JungleDay:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(139, 170, 170, 255)), QGradientStop(1, QColor(174, 139, 156, 255)));
+ case QGradient::PhoenixStart:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(248, 54, 0, 255)), QGradientStop(1, QColor(249, 212, 35, 255)));
+ case QGradient::OctoberSilence:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(183, 33, 255, 255)), QGradientStop(1, QColor(33, 212, 253, 255)));
+ case QGradient::FarawayRiver:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(110, 69, 226, 255)), QGradientStop(1, QColor(136, 211, 206, 255)));
+ case QGradient::AlchemistLab:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(213, 88, 200, 255)), QGradientStop(1, QColor(36, 210, 146, 255)));
+ case QGradient::OverSun:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(171, 236, 214, 255)), QGradientStop(1, QColor(251, 237, 150, 255)));
+ case QGradient::PremiumWhite:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(213, 212, 208, 255)), QGradientStop(0.01, QColor(213, 212, 208, 255)), QGradientStop(0.31, QColor(238, 238, 236, 255)), QGradientStop(0.75, QColor(239, 238, 236, 255)), QGradientStop(1, QColor(233, 233, 231, 255)));
+ case QGradient::MarsParty:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(95, 114, 189, 255)), QGradientStop(1, QColor(155, 35, 234, 255)));
+ case QGradient::EternalConstance:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(9, 32, 63, 255)), QGradientStop(1, QColor(83, 120, 149, 255)));
+ case QGradient::JapanBlush:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(221, 214, 243, 255)), QGradientStop(1, QColor(250, 172, 168, 255)), QGradientStop(1, QColor(250, 172, 168, 255)));
+ case QGradient::SmilingRain:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(220, 176, 237, 255)), QGradientStop(1, QColor(153, 201, 156, 255)));
+ case QGradient::CloudyApple:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(243, 231, 233, 255)), QGradientStop(0.99, QColor(227, 238, 255, 255)), QGradientStop(1, QColor(227, 238, 255, 255)));
+ case QGradient::BigMango:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(199, 29, 111, 255)), QGradientStop(1, QColor(208, 150, 147, 255)));
+ case QGradient::HealthyWater:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(150, 222, 218, 255)), QGradientStop(1, QColor(80, 201, 195, 255)));
+ case QGradient::AmourAmour:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(247, 112, 98, 255)), QGradientStop(1, QColor(254, 81, 150, 255)));
+ case QGradient::RiskyConcrete:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(196, 197, 199, 255)), QGradientStop(0.52, QColor(220, 221, 223, 255)), QGradientStop(1, QColor(235, 235, 235, 255)));
+ case QGradient::StrongStick:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(168, 202, 186, 255)), QGradientStop(1, QColor(93, 65, 87, 255)));
+ case QGradient::ViciousStance:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(41, 50, 60, 255)), QGradientStop(1, QColor(72, 85, 99, 255)));
+ case QGradient::PaloAlto:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(22, 160, 133, 255)), QGradientStop(1, QColor(244, 208, 63, 255)));
+ case QGradient::HappyMemories:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 88, 88, 255)), QGradientStop(1, QColor(240, 152, 25, 255)));
+ case QGradient::MidnightBloom:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(43, 88, 118, 255)), QGradientStop(1, QColor(78, 67, 118, 255)));
+ case QGradient::Crystalline:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(0, 205, 172, 255)), QGradientStop(1, QColor(141, 218, 213, 255)));
+ case QGradient::PartyBliss:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(68, 129, 235, 255)), QGradientStop(1, QColor(4, 190, 254, 255)));
+ case QGradient::ConfidentCloud:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(218, 212, 236, 255)), QGradientStop(0.01, QColor(218, 212, 236, 255)), QGradientStop(1, QColor(243, 231, 233, 255)));
+ case QGradient::LeCocktail:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(135, 77, 162, 255)), QGradientStop(1, QColor(196, 58, 48, 255)));
+ case QGradient::RiverCity:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(68, 129, 235, 255)), QGradientStop(1, QColor(4, 190, 254, 255)));
+ case QGradient::FrozenBerry:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(232, 25, 139, 255)), QGradientStop(1, QColor(199, 234, 253, 255)));
+ case QGradient::ChildCare:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(247, 148, 164, 255)), QGradientStop(1, QColor(253, 214, 189, 255)));
+ case QGradient::FlyingLemon:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(100, 179, 244, 255)), QGradientStop(1, QColor(194, 229, 156, 255)));
+ case QGradient::NewRetrowave:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(59, 65, 197, 255)), QGradientStop(0.49, QColor(169, 129, 187, 255)), QGradientStop(1, QColor(255, 200, 169, 255)));
+ case QGradient::HiddenJaguar:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(15, 216, 80, 255)), QGradientStop(1, QColor(249, 240, 71, 255)));
+ case QGradient::AboveTheSky:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(211, 211, 211, 255)), QGradientStop(0.01, QColor(211, 211, 211, 255)), QGradientStop(0.26, QColor(224, 224, 224, 255)), QGradientStop(0.48, QColor(239, 239, 239, 255)), QGradientStop(0.75, QColor(217, 217, 217, 255)), QGradientStop(1, QColor(188, 188, 188, 255)));
+ case QGradient::Nega:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(238, 156, 167, 255)), QGradientStop(1, QColor(255, 221, 225, 255)));
+ case QGradient::DenseWater:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(58, 181, 176, 255)), QGradientStop(0.31, QColor(61, 153, 190, 255)), QGradientStop(1, QColor(86, 49, 122, 255)));
+ case QGradient::Seashore:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(32, 156, 255, 255)), QGradientStop(1, QColor(104, 224, 207, 255)));
+ case QGradient::MarbleWall:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(189, 194, 232, 255)), QGradientStop(0.01, QColor(189, 194, 232, 255)), QGradientStop(1, QColor(230, 222, 233, 255)));
+ case QGradient::CheerfulCaramel:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(230, 185, 128, 255)), QGradientStop(1, QColor(234, 205, 163, 255)));
+ case QGradient::NightSky:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(30, 60, 114, 255)), QGradientStop(0.01, QColor(30, 60, 114, 255)), QGradientStop(1, QColor(42, 82, 152, 255)));
+ case QGradient::MagicLake:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(213, 222, 231, 255)), QGradientStop(0, QColor(255, 175, 189, 255)), QGradientStop(1, QColor(201, 255, 191, 255)));
+ case QGradient::YoungGrass:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(155, 225, 93, 255)), QGradientStop(1, QColor(0, 227, 174, 255)));
+ case QGradient::ColorfulPeach:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(237, 110, 160, 255)), QGradientStop(1, QColor(236, 140, 105, 255)));
+ case QGradient::GentleCare:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 195, 160, 255)), QGradientStop(1, QColor(255, 175, 189, 255)));
+ case QGradient::PlumBath:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(204, 32, 142, 255)), QGradientStop(1, QColor(103, 19, 210, 255)));
+ case QGradient::HappyUnicorn:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(179, 255, 171, 255)), QGradientStop(1, QColor(18, 255, 247, 255)));
+ case QGradient::AfricanField:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(101, 189, 96, 255)), QGradientStop(0.25, QColor(90, 193, 168, 255)), QGradientStop(0.5, QColor(62, 198, 237, 255)), QGradientStop(0.75, QColor(183, 221, 183, 255)), QGradientStop(1, QColor(254, 243, 129, 255)));
+ case QGradient::SolidStone:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(36, 57, 73, 255)), QGradientStop(1, QColor(81, 127, 164, 255)));
+ case QGradient::OrangeJuice:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(252, 96, 118, 255)), QGradientStop(1, QColor(255, 154, 68, 255)));
+ case QGradient::GlassWater:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(223, 233, 243, 255)), QGradientStop(1, QColor(255, 255, 255, 255)));
+ case QGradient::NorthMiracle:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(0, 219, 222, 255)), QGradientStop(1, QColor(252, 0, 255, 255)));
+ case QGradient::FruitBlend:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(249, 212, 35, 255)), QGradientStop(1, QColor(255, 78, 80, 255)));
+ case QGradient::MillenniumPine:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(80, 204, 127, 255)), QGradientStop(1, QColor(245, 209, 0, 255)));
+ case QGradient::HighFlight:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(10, 207, 254, 255)), QGradientStop(1, QColor(73, 90, 255, 255)));
+ case QGradient::MoleHall:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(97, 97, 97, 255)), QGradientStop(1, QColor(155, 197, 195, 255)));
+ case QGradient::SpaceShift:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(61, 51, 147, 255)), QGradientStop(0.37, QColor(43, 118, 185, 255)), QGradientStop(0.65, QColor(44, 172, 209, 255)), QGradientStop(1, QColor(53, 235, 147, 255)));
+ case QGradient::ForestInei:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(223, 137, 181, 255)), QGradientStop(1, QColor(191, 217, 254, 255)));
+ case QGradient::RoyalGarden:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(237, 110, 160, 255)), QGradientStop(1, QColor(236, 140, 105, 255)));
+ case QGradient::RichMetal:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(215, 210, 204, 255)), QGradientStop(1, QColor(48, 67, 82, 255)));
+ case QGradient::JuicyCake:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(225, 79, 173, 255)), QGradientStop(1, QColor(249, 212, 35, 255)));
+ case QGradient::SmartIndigo:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(178, 36, 239, 255)), QGradientStop(1, QColor(117, 121, 255, 255)));
+ case QGradient::SandStrike:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(193, 193, 97, 255)), QGradientStop(0, QColor(193, 193, 97, 255)), QGradientStop(1, QColor(212, 212, 177, 255)));
+ case QGradient::NorseBeauty:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(236, 119, 171, 255)), QGradientStop(1, QColor(120, 115, 245, 255)));
+ case QGradient::AquaGuidance:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(0, 122, 223, 255)), QGradientStop(1, QColor(0, 236, 188, 255)));
+ case QGradient::SunVeggie:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(32, 226, 215, 255)), QGradientStop(1, QColor(249, 254, 165, 255)));
+ case QGradient::SeaLord:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(44, 216, 213, 255)), QGradientStop(0.56, QColor(197, 193, 255, 255)), QGradientStop(1, QColor(255, 186, 195, 255)));
+ case QGradient::BlackSea:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(44, 216, 213, 255)), QGradientStop(0.48, QColor(107, 141, 214, 255)), QGradientStop(1, QColor(142, 55, 215, 255)));
+ case QGradient::GrassShampoo:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(223, 255, 205, 255)), QGradientStop(0.48, QColor(144, 249, 196, 255)), QGradientStop(1, QColor(57, 243, 187, 255)));
+ case QGradient::LandingAircraft:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(93, 159, 255, 255)), QGradientStop(0.48, QColor(184, 220, 255, 255)), QGradientStop(1, QColor(107, 187, 255, 255)));
+ case QGradient::WitchDance:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(168, 191, 255, 255)), QGradientStop(1, QColor(136, 77, 128, 255)));
+ case QGradient::SleeplessNight:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(82, 113, 196, 255)), QGradientStop(0.48, QColor(177, 159, 255, 255)), QGradientStop(1, QColor(236, 161, 254, 255)));
+ case QGradient::AngelCare:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 226, 159, 255)), QGradientStop(0.48, QColor(255, 169, 159, 255)), QGradientStop(1, QColor(255, 113, 154, 255)));
+ case QGradient::CrystalRiver:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(34, 225, 255, 255)), QGradientStop(0.48, QColor(29, 143, 225, 255)), QGradientStop(1, QColor(98, 94, 177, 255)));
+ case QGradient::SoftLipstick:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(182, 206, 232, 255)), QGradientStop(1, QColor(245, 120, 220, 255)));
+ case QGradient::SaltMountain:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 254, 255, 255)), QGradientStop(1, QColor(215, 255, 254, 255)));
+ case QGradient::PerfectWhite:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(227, 253, 245, 255)), QGradientStop(1, QColor(255, 230, 250, 255)));
+ case QGradient::FreshOasis:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(125, 226, 252, 255)), QGradientStop(1, QColor(185, 182, 229, 255)));
+ case QGradient::StrictNovember:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(203, 186, 204, 255)), QGradientStop(1, QColor(37, 128, 179, 255)));
+ case QGradient::MorningSalad:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(183, 248, 219, 255)), QGradientStop(1, QColor(80, 167, 194, 255)));
+ case QGradient::DeepRelief:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(112, 133, 182, 255)), QGradientStop(0.5, QColor(135, 167, 217, 255)), QGradientStop(1, QColor(222, 243, 248, 255)));
+ case QGradient::SeaStrike:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(119, 255, 210, 255)), QGradientStop(0.48, QColor(98, 151, 219, 255)), QGradientStop(1, QColor(30, 236, 255, 255)));
+ case QGradient::NightCall:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(172, 50, 228, 255)), QGradientStop(0.48, QColor(121, 24, 242, 255)), QGradientStop(1, QColor(72, 1, 255, 255)));
+ case QGradient::SupremeSky:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(212, 255, 236, 255)), QGradientStop(0.48, QColor(87, 242, 204, 255)), QGradientStop(1, QColor(69, 150, 251, 255)));
+ case QGradient::LightBlue:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(158, 251, 211, 255)), QGradientStop(0.48, QColor(87, 233, 242, 255)), QGradientStop(1, QColor(69, 212, 251, 255)));
+ case QGradient::MindCrawl:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(71, 59, 123, 255)), QGradientStop(0.51, QColor(53, 132, 167, 255)), QGradientStop(1, QColor(48, 210, 190, 255)));
+ case QGradient::LilyMeadow:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(101, 55, 155, 255)), QGradientStop(0.53, QColor(136, 106, 234, 255)), QGradientStop(1, QColor(100, 87, 198, 255)));
+ case QGradient::SugarLollipop:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(164, 69, 178, 255)), QGradientStop(0.52, QColor(212, 24, 114, 255)), QGradientStop(1, QColor(255, 0, 102, 255)));
+ case QGradient::SweetDessert:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(119, 66, 178, 255)), QGradientStop(0.52, QColor(241, 128, 255, 255)), QGradientStop(1, QColor(253, 139, 217, 255)));
+ case QGradient::MagicRay:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 60, 172, 255)), QGradientStop(0.52, QColor(86, 43, 124, 255)), QGradientStop(1, QColor(43, 134, 197, 255)));
+ case QGradient::TeenParty:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 5, 124, 255)), QGradientStop(0.5, QColor(141, 11, 147, 255)), QGradientStop(1, QColor(50, 21, 117, 255)));
+ case QGradient::FrozenHeat:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(255, 5, 124, 255)), QGradientStop(0.48, QColor(124, 100, 213, 255)), QGradientStop(1, QColor(76, 195, 255, 255)));
+ case QGradient::GagarinView:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(105, 234, 203, 255)), QGradientStop(0.48, QColor(234, 204, 248, 255)), QGradientStop(1, QColor(102, 84, 241, 255)));
+ case QGradient::FabledSunset:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(35, 21, 87, 255)), QGradientStop(0.29, QColor(68, 16, 122, 255)), QGradientStop(0.67, QColor(255, 19, 97, 255)), QGradientStop(1, QColor(255, 248, 0, 255)));
+ case QGradient::PerfectBlue:
+ return Q_ARRAY_LITERAL(QGradientStop, QGradientStop(0, QColor(61, 78, 129, 255)), QGradientStop(0.48, QColor(87, 83, 201, 255)), QGradientStop(1, QColor(110, 127, 243, 255)));
+ case QGradient::NumPresets:
+ Q_UNREACHABLE();
+ }
+ Q_UNREACHABLE_RETURN({});
+}
+
+static constexpr QGradient::QGradientData qt_preset_gradient_data[] = {
+ { { 0, 1, 1, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 0, 0 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { -0.0915064, 0.158494, 1.09151, 0.841506 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 0, 0.5, 1 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.341506, 1.09151, 0.658494, -0.0915064 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 0, 0 } },
+ { { 0, 1, 1, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 1, 1, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 1, 1, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { -0.0915064, 0.841506, 1.09151, 0.158494 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { -0.0915064, 0.841506, 1.09151, 0.158494 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { -0.0915064, 0.841506, 1.09151, 0.158494 } },
+ { { 1.09151, 0.841506, -0.0915064, 0.158494 } },
+ { { 1.09151, 0.841506, -0.0915064, 0.158494 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 1, 1, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { -0.0915064, 0.841506, 1.09151, 0.158494 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 1, 1, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 0, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 0, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.719186, 1.10221, 0.280814, -0.102208 } },
+ { { 0, 0, 0, 0 } },
+ { { -0.0915064, 0.841506, 1.09151, 0.158494 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0, 0.5, 1, 0.5 } },
+ { { 0.5, 1, 0.5, 0 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+ { { 0, 0, 1, 1 } },
+};
diff --git a/src/gui/painting/webgradients.css b/src/gui/painting/webgradients.css
deleted file mode 100644
index 870866bb46..0000000000
--- a/src/gui/painting/webgradients.css
+++ /dev/null
@@ -1,909 +0,0 @@
-/*001 Warm Flame*/
-.warm_flame{
- background-image: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%);
-}
-
-/*002 Night Fade*/
-.night_fade{
- background-image: linear-gradient(to top, #a18cd1 0%, #fbc2eb 100%);
-}
-
-/*003 Spring Warmth*/
-.spring_warmth{
- background-image: linear-gradient(to top, #fad0c4 0%, #fad0c4 1%, #ffd1ff 100%);
-}
-
-/*004 Juicy Peach*/
-.juicy_peach{
- background-image: linear-gradient(to right, #ffecd2 0%, #fcb69f 100%);
-}
-
-/*005 Young Passion*/
-.young_passion{
- background-image: linear-gradient(to right, #ff8177 0%, #ff867a 0%, #ff8c7f 21%, #f99185 52%, #cf556c 78%, #b12a5b 100%);
-}
-
-/*006 Lady Lips*/
-.lady_lips{
- background-image: linear-gradient(to top, #ff9a9e 0%, #fecfef 99%, #fecfef 100%);
-}
-
-/*007 Sunny Morning*/
-.sunny_morning{
- background-image: linear-gradient(120deg, #f6d365 0%, #fda085 100%);
-}
-
-/*008 Rainy Ashville*/
-.rainy_ashville{
- background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%);
-}
-
-/*009 Frozen Dreams*/
-.frozen_dreams{
- background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
-}
-
-/*010 Winter Neva*/
-.winter_neva{
- background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
-}
-
-/*011 Dusty Grass*/
-.dusty_grass{
- background-image: linear-gradient(120deg, #d4fc79 0%, #96e6a1 100%);
-}
-
-/*012 Tempting Azure*/
-.tempting_azure{
- background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
-}
-
-/*013 Heavy Rain*/
-.heavy_rain{
- background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
-}
-
-/*014 Amy Crisp*/
-.amy_crisp{
- background-image: linear-gradient(120deg, #a6c0fe 0%, #f68084 100%);
-}
-
-/*015 Mean Fruit*/
-.mean_fruit{
- background-image: linear-gradient(120deg, #fccb90 0%, #d57eeb 100%);
-}
-
-/*016 Deep Blue*/
-.deep_blue{
- background-image: linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 100%);
-}
-
-/*017 Ripe Malinka*/
-.ripe_malinka{
- background-image: linear-gradient(120deg, #f093fb 0%, #f5576c 100%);
-}
-
-/*018 Cloudy Knoxville*/
-.cloudy_knoxville{
- background-image: linear-gradient(120deg, #fdfbfb 0%, #ebedee 100%);
-}
-
-/*019 Malibu Beach*/
-.malibu_beach{
- background-image: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
-}
-
-/*020 New Life*/
-.new_life{
- background-image: linear-gradient(to right, #43e97b 0%, #38f9d7 100%);
-}
-
-/*021 True Sunset*/
-.true_sunset{
- background-image: linear-gradient(to right, #fa709a 0%, #fee140 100%);
-}
-
-/*022 Morpheus Den*/
-.morpheus_den{
- background-image: linear-gradient(to top, #30cfd0 0%, #330867 100%);
-}
-
-/*023 Rare Wind*/
-.rare_wind{
- background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
-}
-
-/*024 Near Moon*/
-.near_moon{
- background-image: linear-gradient(to top, #5ee7df 0%, #b490ca 100%);
-}
-
-/*025 Wild Apple*/
-.wild_apple{
- background-image: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
-}
-
-/*026 Saint Petersburg*/
-.saint_petersburg{
- background-image: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
-}
-
-/*027 Arielle's Smile*/
-.arielles_smile{
- background-image: radial-gradient(circle 248px at center, #16d9e3 0%, #30c7ec 47%, #46aef7 100%);
-}
-
-/*028 Plum Plate*/
-.plum_plate{
- background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-}
-
-/*029 Everlasting Sky*/
-.everlasting_sky{
- background-image: linear-gradient(135deg, #fdfcfb 0%, #e2d1c3 100%);
-}
-
-/*030 Happy Fisher*/
-.happy_fisher{
- background-image: linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%);
-}
-
-/*031 Blessing*/
-.blessing{
- background-image: linear-gradient(to top, #fddb92 0%, #d1fdff 100%);
-}
-
-/*032 Sharpeye Eagle*/
-.sharpeye_eagle{
- background-image: linear-gradient(to top, #9890e3 0%, #b1f4cf 100%);
-}
-
-/*033 Ladoga Bottom*/
-.ladoga_bottom{
- background-image: linear-gradient(to top, #ebc0fd 0%, #d9ded8 100%);
-}
-
-/*034 Lemon Gate*/
-.lemon_gate{
- background-image: linear-gradient(to top, #96fbc4 0%, #f9f586 100%);
-}
-
-/*035 Itmeo Branding*/
-.itmeo_branding{
- background-image: linear-gradient(180deg, #2af598 0%, #009efd 100%);
-}
-
-/*036 Zeus Miracle*/
-.zeus_miracle{
- background-image: linear-gradient(to top, #cd9cf2 0%, #f6f3ff 100%);
-}
-
-/*037 Old Hat*/
-.old_hat{
- background-image: linear-gradient(to right, #e4afcb 0%, #b8cbb8 0%, #b8cbb8 0%, #e2c58b 30%, #c2ce9c 64%, #7edbdc 100%);
-}
-
-/*038 Star Wine*/
-.star_wine{
- background-image: linear-gradient(to right, #b8cbb8 0%, #b8cbb8 0%, #b465da 0%, #cf6cc9 33%, #ee609c 66%, #ee609c 100%);
-}
-
-/*039 Deep Blue*/
-.deep_blue{
- background-image: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);
-}
-
-/*040 Coup de Grace*/
-.coup_de_grace{
- background: #DCD9D4 linear-gradient(to bottom, rgba(255, 255, 255, 0.50) 0%, rgba(0, 0, 0, 0.50) 100%), radial-gradient(at 50% 0%, rgba(255, 255, 255, 0.10) 0%, rgba(0, 0, 0, 0.50) 50%);
- background-blend-mode: soft-light,screen;
-}
-
-/*041 Happy Acid*/
-.happy_acid{
- background-image: linear-gradient(to top, #37ecba 0%, #72afd3 100%);
-}
-
-/*042 Awesome Pine*/
-.awesome_pine{
- background-image: linear-gradient(to top, #ebbba7 0%, #cfc7f8 100%);
-}
-
-/*043 New York*/
-.new_york{
- background-image: linear-gradient(to top, #fff1eb 0%, #ace0f9 100%);
-}
-
-/*044 Shy Rainbow*/
-.shy_rainbow{
- background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%);
-}
-
-/*045 Loon Crest*/
-.loon_crest{
- background: linear-gradient(to bottom, rgba(255,255,255,0.15) 0%, rgba(0,0,0,0.15) 100%), radial-gradient(at top center, rgba(255,255,255,0.40) 0%, rgba(0,0,0,0.40) 120%) #989898;
- background-blend-mode: multiply,multiply;
-}
-
-/*046 Mixed Hopes*/
-.mixed_hopes{
- background-image: linear-gradient(to top, #c471f5 0%, #fa71cd 100%);
-}
-
-/*047 Fly High*/
-.fly_high{
- background-image: linear-gradient(to top, #48c6ef 0%, #6f86d6 100%);
-}
-
-/*048 Strong Bliss*/
-.strong_bliss{
- background-image: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);
-}
-
-/*049 Fresh Milk*/
-.fresh_milk{
- background-image: linear-gradient(to top, #feada6 0%, #f5efef 100%);
-}
-
-/*050 Snow Again*/
-.snow_again{
- background-image: linear-gradient(to top, #e6e9f0 0%, #eef1f5 100%);
-}
-
-/*051 February Ink*/
-.february_ink{
- background-image: linear-gradient(to top, #accbee 0%, #e7f0fd 100%);
-}
-
-/*052 Kind Steel*/
-.kind_steel{
- background-image: linear-gradient(-20deg, #e9defa 0%, #fbfcdb 100%);
-}
-
-/*053 Soft Grass*/
-.soft_grass{
- background-image: linear-gradient(to top, #c1dfc4 0%, #deecdd 100%);
-}
-
-/*054 Grown Early*/
-.grown_early{
- background-image: linear-gradient(to top, #0ba360 0%, #3cba92 100%);
-}
-
-/*055 Sharp Blues*/
-.sharp_blues{
- background-image: linear-gradient(to top, #00c6fb 0%, #005bea 100%);
-}
-
-/*056 Shady Water*/
-.shady_water{
- background-image: linear-gradient(to right, #74ebd5 0%, #9face6 100%);
-}
-
-/*057 Dirty Beauty*/
-.dirty_beauty{
- background-image: linear-gradient(to top, #6a85b6 0%, #bac8e0 100%);
-}
-
-/*058 Great Whale*/
-.great_whale{
- background-image: linear-gradient(to top, #a3bded 0%, #6991c7 100%);
-}
-
-/*059 Teen Notebook*/
-.teen_notebook{
- background-image: linear-gradient(to top, #9795f0 0%, #fbc8d4 100%);
-}
-
-/*060 Polite Rumors*/
-.polite_rumors{
- background-image: linear-gradient(to top, #a7a6cb 0%, #8989ba 52%, #8989ba 100%);
-}
-
-/*061 Sweet Period*/
-.sweet_period{
- background-image: linear-gradient(to top, #3f51b1 0%, #5a55ae 13%, #7b5fac 25%, #8f6aae 38%, #a86aa4 50%, #cc6b8e 62%, #f18271 75%, #f3a469 87%, #f7c978 100%);
-}
-
-/*062 Wide Matrix*/
-.wide_matrix{
- background-image: linear-gradient(to top, #fcc5e4 0%, #fda34b 15%, #ff7882 35%, #c8699e 52%, #7046aa 71%, #0c1db8 87%, #020f75 100%);
-}
-
-/*063 Soft Cherish*/
-.soft_cherish{
- background-image: linear-gradient(to top, #dbdcd7 0%, #dddcd7 24%, #e2c9cc 30%, #e7627d 46%, #b8235a 59%, #801357 71%, #3d1635 84%, #1c1a27 100%);
-}
-
-/*064 Red Salvation*/
-.red_salvation{
- background-image: linear-gradient(to top, #f43b47 0%, #453a94 100%);
-}
-
-/*065 Burning Spring*/
-.burning_spring{
- background-image: linear-gradient(to top, #4fb576 0%, #44c489 30%, #28a9ae 46%, #28a2b7 59%, #4c7788 71%, #6c4f63 86%, #432c39 100%);
-}
-
-/*066 Night Party*/
-.night_party{
- background-image: linear-gradient(to top, #0250c5 0%, #d43f8d 100%);
-}
-
-/*067 Sky Glider*/
-.sky_glider{
- background-image: linear-gradient(to top, #88d3ce 0%, #6e45e2 100%);
-}
-
-/*068 Heaven Peach*/
-.heaven_peach{
- background-image: linear-gradient(to top, #d9afd9 0%, #97d9e1 100%);
-}
-
-/*069 Purple Division*/
-.purple_division{
- background-image: linear-gradient(to top, #7028e4 0%, #e5b2ca 100%);
-}
-
-/*070 Aqua Splash*/
-.aqua_splash{
- background-image: linear-gradient(15deg, #13547a 0%, #80d0c7 100%);
-}
-
-/*071 Above Clouds*/
-.above_clouds{
- background-image: linear-gradient(to left, #BDBBBE 0%, #9D9EA3 100%), radial-gradient(88% 271%, rgba(255, 255, 255, 0.25) 0%, rgba(254, 254, 254, 0.25) 1%, rgba(0, 0, 0, 0.25) 100%), radial-gradient(50% 100%, rgba(255, 255, 255, 0.30) 0%, rgba(0, 0, 0, 0.30) 100%);
- background-blend-mode: normal, lighten, soft-light;
-}
-
-/*072 Spiky Naga*/
-.spiky_naga{
- background-image: linear-gradient(to top, #505285 0%, #585e92 12%, #65689f 25%, #7474b0 37%, #7e7ebb 50%, #8389c7 62%, #9795d4 75%, #a2a1dc 87%, #b5aee4 100%);
-}
-
-/*073 Love Kiss*/
-.love_kiss{
- background-image: linear-gradient(to top, #ff0844 0%, #ffb199 100%);
-}
-
-/*074 Sharp Glass*/
-.sharp_glass{
- background: #C9CCD3 linear-gradient(-180deg, rgba(255, 255, 255, 0.50) 0%, rgba(0, 0, 0, 0.50) 100%);
- background-blend-mode: lighten;
-}
-
-/*075 Clean Mirror*/
-.clean_mirror{
- background-image: linear-gradient(45deg, #93a5cf 0%, #e4efe9 100%);
-}
-
-/*076 Premium Dark*/
-.premium_dark{
- background-image: linear-gradient(to right, #434343 0%, black 100%);
-}
-
-/*077 Cold Evening*/
-.cold_evening{
- background-image: linear-gradient(to top, #0c3483 0%, #a2b6df 100%, #6b8cce 100%, #a2b6df 100%);
-}
-
-/*078 Cochiti Lake*/
-.cochiti_lake{
- background-image: linear-gradient(45deg, #93a5cf 0%, #e4efe9 100%);
-}
-
-/*079 Summer Games*/
-.summer_games{
- background-image: linear-gradient(to right, #92fe9d 0%, #00c9ff 100%);
-}
-
-/*080 Passionate Bed*/
-.passionate_bed{
- background-image: linear-gradient(to right, #ff758c 0%, #ff7eb3 100%);
-}
-
-/*081 Mountain Rock*/
-.mountain_rock{
- background-image: linear-gradient(to right, #868f96 0%, #596164 100%);
-}
-
-/*082 Desert Hump*/
-.desert_hump{
- background-image: linear-gradient(to top, #c79081 0%, #dfa579 100%);
-}
-
-/*083 Jungle Day*/
-.jungle_day{
- background-image: linear-gradient(45deg, #8baaaa 0%, #ae8b9c 100%);
-}
-
-/*084 Phoenix Start*/
-.phoenix_start{
- background-image: linear-gradient(to right, #f83600 0%, #f9d423 100%);
-}
-
-/*085 October Silence*/
-.october_silence{
- background-image: linear-gradient(-20deg, #b721ff 0%, #21d4fd 100%);
-}
-
-/*086 Faraway River*/
-.faraway_river{
- background-image: linear-gradient(-20deg, #6e45e2 0%, #88d3ce 100%);
-}
-
-/*087 Alchemist Lab*/
-.alchemist_lab{
- background-image: linear-gradient(-20deg, #d558c8 0%, #24d292 100%);
-}
-
-/*088 Over Sun*/
-.over_sun{
- background-image: linear-gradient(60deg, #abecd6 0%, #fbed96 100%);
-}
-
-/*089 Premium White*/
-.premium_white{
- background-image: linear-gradient(to top, #d5d4d0 0%, #d5d4d0 1%, #eeeeec 31%, #efeeec 75%, #e9e9e7 100%);
-}
-
-/*090 Mars Party*/
-.mars_party{
- background-image: linear-gradient(to top, #5f72bd 0%, #9b23ea 100%);
-}
-
-/*091 Eternal Constance*/
-.eternal_constance{
- background-image: linear-gradient(to top, #09203f 0%, #537895 100%);
-}
-
-/*092 Japan Blush*/
-.japan_blush{
- background-image: linear-gradient(-20deg, #ddd6f3 0%, #faaca8 100%, #faaca8 100%);
-}
-
-/*093 Smiling Rain*/
-.smiling_rain{
- background-image: linear-gradient(-20deg, #dcb0ed 0%, #99c99c 100%);
-}
-
-/*094 Cloudy Apple*/
-.cloudy_apple{
- background-image: linear-gradient(to top, #f3e7e9 0%, #e3eeff 99%, #e3eeff 100%);
-}
-
-/*095 Big Mango*/
-.big_mango{
- background-image: linear-gradient(to top, #c71d6f 0%, #d09693 100%);
-}
-
-/*096 Healthy Water*/
-.healthy_water{
- background-image: linear-gradient(60deg, #96deda 0%, #50c9c3 100%);
-}
-
-/*097 Amour Amour*/
-.amour_amour{
- background-image: linear-gradient(to top, #f77062 0%, #fe5196 100%);
-}
-
-/*098 Risky Concrete*/
-.risky_concrete{
- background-image: linear-gradient(to top, #c4c5c7 0%, #dcdddf 52%, #ebebeb 100%);
-}
-
-/*099 Strong Stick*/
-.strong_stick{
- background-image: linear-gradient(to right, #a8caba 0%, #5d4157 100%);
-}
-
-/*100 Vicious Stance*/
-.vicious_stance{
- background-image: linear-gradient(60deg, #29323c 0%, #485563 100%);
-}
-
-/*101 Palo Alto*/
-.palo_alto{
- background-image: linear-gradient(-60deg, #16a085 0%, #f4d03f 100%);
-}
-
-/*102 Happy Memories*/
-.happy_memories{
- background-image: linear-gradient(-60deg, #ff5858 0%, #f09819 100%);
-}
-
-/*103 Midnight Bloom*/
-.midnight_bloom{
- background-image: linear-gradient(-20deg, #2b5876 0%, #4e4376 100%);
-}
-
-/*104 Crystalline*/
-.crystalline{
- background-image: linear-gradient(-20deg, #00cdac 0%, #8ddad5 100%);
-}
-
-/*105 Raccoon Back*/
-.raccoon_back{
- background: linear-gradient(-180deg, #BCC5CE 0%, #929EAD 98%), radial-gradient(at top left, rgba(255,255,255,0.30) 0%, rgba(0,0,0,0.30) 100%);
- background-blend-mode: screen;
-}
-
-/*106 Party Bliss*/
-.party_bliss{
- background-image: linear-gradient(to top, #4481eb 0%, #04befe 100%);
-}
-
-/*107 Confident Cloud*/
-.confident_cloud{
- background-image: linear-gradient(to top, #dad4ec 0%, #dad4ec 1%, #f3e7e9 100%);
-}
-
-/*108 Le Cocktail*/
-.le_cocktail{
- background-image: linear-gradient(45deg, #874da2 0%, #c43a30 100%);
-}
-
-/*109 River City*/
-.river_city{
- background-image: linear-gradient(to top, #4481eb 0%, #04befe 100%);
-}
-
-/*110 Frozen Berry*/
-.frozen_berry{
- background-image: linear-gradient(to top, #e8198b 0%, #c7eafd 100%);
-}
-
-/*111 Elegance*/
-.elegance{
- background-image: radial-gradient(73% 147%, #EADFDF 59%, #ECE2DF 100%), radial-gradient(91% 146%, rgba(255,255,255,0.50) 47%, rgba(0,0,0,0.50) 100%);
- background-blend-mode: screen;
-}
-
-/*112 Child Care*/
-.child_care{
- background-image: linear-gradient(-20deg, #f794a4 0%, #fdd6bd 100%);
-}
-
-/*113 Flying Lemon*/
-.flying_lemon{
- background-image: linear-gradient(60deg, #64b3f4 0%, #c2e59c 100%);
-}
-
-/*114 New Retrowave*/
-.new_retrowave{
- background-image: linear-gradient(to top, #3b41c5 0%, #a981bb 49%, #ffc8a9 100%);
-}
-
-/*115 Hidden Jaguar*/
-.hidden_jaguar{
- background-image: linear-gradient(to top, #0fd850 0%, #f9f047 100%);
-}
-
-/*116 Above The Sky*/
-.above_the_sky{
- background-image: linear-gradient(to top, lightgrey 0%, lightgrey 1%, #e0e0e0 26%, #efefef 48%, #d9d9d9 75%, #bcbcbc 100%);
-}
-
-/*117 Nega*/
-.nega{
- background-image: linear-gradient(45deg, #ee9ca7 0%, #ffdde1 100%);
-}
-
-/*118 Dense Water*/
-.dense_water{
- background-image: linear-gradient(to right, #3ab5b0 0%, #3d99be 31%, #56317a 100%);
-}
-
-/*119 Chemic Aqua*/
-.chemic_aqua{
- background: #CDDCDC radial-gradient(at 50% 100%, rgba(255, 255, 255, 0.50) 0%, rgba(0, 0, 0, 0.50) 100%), linear-gradient(to bottom, rgba(255, 255, 255, 0.25) 0%, rgba(0, 0, 0, 0.25) 100%);
- background-blend-mode: screen, overlay;
-}
-
-/*120 Seashore*/
-.seashore{
- background-image: linear-gradient(to top, #209cff 0%, #68e0cf 100%);
-}
-
-/*121 Marble Wall*/
-.marble_wall{
- background-image: linear-gradient(to top, #bdc2e8 0%, #bdc2e8 1%, #e6dee9 100%);
-}
-
-/*122 Cheerful Caramel*/
-.cheerful_caramel{
- background-image: linear-gradient(to top, #e6b980 0%, #eacda3 100%);
-}
-
-/*123 Night Sky*/
-.night_sky{
- background-image: linear-gradient(to top, #1e3c72 0%, #1e3c72 1%, #2a5298 100%);
-}
-
-/*124 Magic Lake*/
-.magic_lake{
- background-image: linear-gradient(to top, #d5dee7 0%, #ffafbd 0%, #c9ffbf 100%);
-}
-
-/*125 Young Grass*/
-.young_grass{
- background-image: linear-gradient(to top, #9be15d 0%, #00e3ae 100%);
-}
-
-/*126 Colorful Peach*/
-.colorful_peach{
- background-image: linear-gradient(to right, #ed6ea0 0%, #ec8c69 100%);
-}
-
-/*127 Gentle Care*/
-.gentle_care{
- background-image: linear-gradient(to right, #ffc3a0 0%, #ffafbd 100%);
-}
-
-/*128 Plum Bath*/
-.plum_bath{
- background-image: linear-gradient(to top, #cc208e 0%, #6713d2 100%);
-}
-
-/*129 Happy Unicorn*/
-.happy_unicorn{
- background-image: linear-gradient(to top, #b3ffab 0%, #12fff7 100%);
-}
-
-/*130 Full Metal*/
-.full_metal{
- background: linear-gradient(to bottom, #D5DEE7 0%, #E8EBF2 50%, #E2E7ED 100%), linear-gradient(to bottom, rgba(0,0,0,0.02) 50%, rgba(255,255,255,0.02) 61%, rgba(0,0,0,0.02) 73%), linear-gradient(33deg, rgba(255,255,255,0.20) 0%, rgba(0,0,0,0.20) 100%);
- background-blend-mode: normal,color-burn;
-}
-
-/*131 African Field*/
-.african_field{
- background-image: linear-gradient(to top, #65bd60 0%, #5ac1a8 25%, #3ec6ed 50%, #b7ddb7 75%, #fef381 100%);
-}
-
-/*132 Solid Stone*/
-.solid_stone{
- background-image: linear-gradient(to right, #243949 0%, #517fa4 100%);
-}
-
-/*133 Orange Juice*/
-.orange_juice{
- background-image: linear-gradient(-20deg, #fc6076 0%, #ff9a44 100%);
-}
-
-/*134 Glass Water*/
-.glass_water{
- background-image: linear-gradient(to top, #dfe9f3 0%, white 100%);
-}
-
-/*135 Slick Carbon*/
-.slick_carbon{
- background: linear-gradient(to bottom, #323232 0%, #3F3F3F 40%, #1C1C1C 150%), linear-gradient(to top, rgba(255,255,255,0.40) 0%, rgba(0,0,0,0.25) 200%);
- background-blend-mode: multiply;
-}
-
-/*136 North Miracle*/
-.north_miracle{
- background-image: linear-gradient(to right, #00dbde 0%, #fc00ff 100%);
-}
-
-/*137 Fruit Blend*/
-.fruit_blend{
- background-image: linear-gradient(to right, #f9d423 0%, #ff4e50 100%);
-}
-
-/*138 Millennium Pine*/
-.millennium_pine{
- background-image: linear-gradient(to top, #50cc7f 0%, #f5d100 100%);
-}
-
-/*139 High Flight*/
-.high_flight{
- background-image: linear-gradient(to right, #0acffe 0%, #495aff 100%);
-}
-
-/*140 Mole Hall*/
-.mole_hall{
- background-image: linear-gradient(-20deg, #616161 0%, #9bc5c3 100%);
-}
-
-/*141 Earl Gray*/
-.earl_gray{
- background: #E4E4E1 radial-gradient(at top center, rgba(255, 255, 255, 0.03) 0%, rgba(0, 0, 0, 0.03) 100%), linear-gradient(to top, rgba(255, 255, 255, 0.1) 0%, rgba(143, 152, 157, 0.60) 100%);
- background-blend-mode: normal, multiply;
-}
-
-/*142 Space Shift*/
-.space_shift{
- background-image: linear-gradient(60deg, #3d3393 0%, #2b76b9 37%, #2cacd1 65%, #35eb93 100%);
-}
-
-/*143 Forest Inei*/
-.forest_inei{
- background-image: linear-gradient(to top, #df89b5 0%, #bfd9fe 100%);
-}
-
-/*144 Royal Garden*/
-.royal_garden{
- background-image: linear-gradient(to right, #ed6ea0 0%, #ec8c69 100%);
-}
-
-/*145 Rich Metal*/
-.rich_metal{
- background-image: linear-gradient(to right, #d7d2cc 0%, #304352 100%);
-}
-
-/*146 Juicy Cake*/
-.juicy_cake{
- background-image: linear-gradient(to top, #e14fad 0%, #f9d423 100%);
-}
-
-/*147 Smart Indigo*/
-.smart_indigo{
- background-image: linear-gradient(to top, #b224ef 0%, #7579ff 100%);
-}
-
-/*148 Sand Strike*/
-.sand_strike{
- background-image: linear-gradient(to right, #c1c161 0%, #c1c161 0%, #d4d4b1 100%);
-}
-
-/*149 Norse Beauty*/
-.norse_beauty{
- background-image: linear-gradient(to right, #ec77ab 0%, #7873f5 100%);
-}
-
-/*150 Aqua Guidance*/
-.aqua_guidance{
- background-image: linear-gradient(to top, #007adf 0%, #00ecbc 100%);
-}
-
-/*151 Sun Veggie*/
-.sun_veggie{
- background-image: linear-gradient(-225deg, #20E2D7 0%, #F9FEA5 100%);
-}
-
-/*152 Sea Lord*/
-.sea_lord{
- background-image: linear-gradient(-225deg, #2CD8D5 0%, #C5C1FF 56%, #FFBAC3 100%);
-}
-
-/*153 Black Sea*/
-.black_sea{
- background-image: linear-gradient(-225deg, #2CD8D5 0%, #6B8DD6 48%, #8E37D7 100%);
-}
-
-/*154 Grass Shampoo*/
-.grass_shampoo{
- background-image: linear-gradient(-225deg, #DFFFCD 0%, #90F9C4 48%, #39F3BB 100%);
-}
-
-/*155 Landing Aircraft*/
-.landing_aircraft{
- background-image: linear-gradient(-225deg, #5D9FFF 0%, #B8DCFF 48%, #6BBBFF 100%);
-}
-
-/*156 Witch Dance*/
-.witch_dance{
- background-image: linear-gradient(-225deg, #A8BFFF 0%, #884D80 100%);
-}
-
-/*157 Sleepless Night*/
-.sleepless_night{
- background-image: linear-gradient(-225deg, #5271C4 0%, #B19FFF 48%, #ECA1FE 100%);
-}
-
-/*158 Angel Care*/
-.angel_care{
- background-image: linear-gradient(-225deg, #FFE29F 0%, #FFA99F 48%, #FF719A 100%);
-}
-
-/*159 Crystal River*/
-.crystal_river{
- background-image: linear-gradient(-225deg, #22E1FF 0%, #1D8FE1 48%, #625EB1 100%);
-}
-
-/*160 Soft Lipstick*/
-.soft_lipstick{
- background-image: linear-gradient(-225deg, #B6CEE8 0%, #F578DC 100%);
-}
-
-/*161 Salt Mountain*/
-.salt_mountain{
- background-image: linear-gradient(-225deg, #FFFEFF 0%, #D7FFFE 100%);
-}
-
-/*162 Perfect White*/
-.perfect_white{
- background-image: linear-gradient(-225deg, #E3FDF5 0%, #FFE6FA 100%);
-}
-
-/*163 Fresh Oasis*/
-.fresh_oasis{
- background-image: linear-gradient(-225deg, #7DE2FC 0%, #B9B6E5 100%);
-}
-
-/*164 Strict November*/
-.strict_november{
- background-image: linear-gradient(-225deg, #CBBACC 0%, #2580B3 100%);
-}
-
-/*165 Morning Salad*/
-.morning_salad{
- background-image: linear-gradient(-225deg, #B7F8DB 0%, #50A7C2 100%);
-}
-
-/*166 Deep Relief*/
-.deep_relief{
- background-image: linear-gradient(-225deg, #7085B6 0%, #87A7D9 50%, #DEF3F8 100%);
-}
-
-/*167 Sea Strike*/
-.sea_strike{
- background-image: linear-gradient(-225deg, #77FFD2 0%, #6297DB 48%, #1EECFF 100%);
-}
-
-/*168 Night Call*/
-.night_call{
- background-image: linear-gradient(-225deg, #AC32E4 0%, #7918F2 48%, #4801FF 100%);
-}
-
-/*169 Supreme Sky*/
-.supreme_sky{
- background-image: linear-gradient(-225deg, #D4FFEC 0%, #57F2CC 48%, #4596FB 100%);
-}
-
-/*170 Light Blue*/
-.light_blue{
- background-image: linear-gradient(-225deg, #9EFBD3 0%, #57E9F2 48%, #45D4FB 100%);
-}
-
-/*171 Mind Crawl*/
-.mind_crawl{
- background-image: linear-gradient(-225deg, #473B7B 0%, #3584A7 51%, #30D2BE 100%);
-}
-
-/*172 Lily Meadow*/
-.lily_meadow{
- background-image: linear-gradient(-225deg, #65379B 0%, #886AEA 53%, #6457C6 100%);
-}
-
-/*173 Sugar Lollipop*/
-.sugar_lollipop{
- background-image: linear-gradient(-225deg, #A445B2 0%, #D41872 52%, #FF0066 100%);
-}
-
-/*174 Sweet Dessert*/
-.sweet_dessert{
- background-image: linear-gradient(-225deg, #7742B2 0%, #F180FF 52%, #FD8BD9 100%);
-}
-
-/*175 Magic Ray*/
-.magic_ray{
- background-image: linear-gradient(-225deg, #FF3CAC 0%, #562B7C 52%, #2B86C5 100%);
-}
-
-/*176 Teen Party*/
-.teen_party{
- background-image: linear-gradient(-225deg, #FF057C 0%, #8D0B93 50%, #321575 100%);
-}
-
-/*177 Frozen Heat*/
-.frozen_heat{
- background-image: linear-gradient(-225deg, #FF057C 0%, #7C64D5 48%, #4CC3FF 100%);
-}
-
-/*178 Gagarin View*/
-.gagarin_view{
- background-image: linear-gradient(-225deg, #69EACB 0%, #EACCF8 48%, #6654F1 100%);
-}
-
-/*179 Fabled Sunset*/
-.fabled_sunset{
- background-image: linear-gradient(-225deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%);
-}
-
-/*180 Perfect Blue*/
-.perfect_blue{
- background-image: linear-gradient(-225deg, #3D4E81 0%, #5753C9 48%, #6E7FF3 100%);
-}