summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/accessible/qaccessible.cpp26
-rw-r--r--src/gui/configure.json78
-rw-r--r--src/gui/image/image.pri2
-rw-r--r--src/gui/image/qbitmap.cpp52
-rw-r--r--src/gui/image/qbitmap.h1
-rw-r--r--src/gui/image/qimage.cpp59
-rw-r--r--src/gui/image/qimage_conversions.cpp18
-rw-r--r--src/gui/image/qimagereader.cpp117
-rw-r--r--src/gui/image/qimagereader.h1
-rw-r--r--src/gui/image/qimagereaderwriterhelpers.cpp180
-rw-r--r--src/gui/image/qimagereaderwriterhelpers_p.h139
-rw-r--r--src/gui/image/qimagewriter.cpp121
-rw-r--r--src/gui/image/qimagewriter.h1
-rw-r--r--src/gui/image/qpixmap.cpp10
-rw-r--r--src/gui/image/qxbmhandler.cpp2
-rw-r--r--src/gui/image/qxpmhandler.cpp4
-rw-r--r--src/gui/kernel/qevent.cpp41
-rw-r--r--src/gui/kernel/qevent.h8
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h1
-rw-r--r--src/gui/kernel/qplatformwindow.cpp34
-rw-r--r--src/gui/kernel/qplatformwindow.h2
-rw-r--r--src/gui/kernel/qshortcutmap.cpp13
-rw-r--r--src/gui/kernel/qwindow.cpp26
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp4
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h1
-rw-r--r--src/gui/opengl/qopengl.h2
-rw-r--r--src/gui/opengl/qopenglengineshadermanager.cpp56
-rw-r--r--src/gui/opengl/qopenglengineshadermanager_p.h4
-rw-r--r--src/gui/opengl/qopenglengineshadersource_p.h159
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp23
-rw-r--r--src/gui/opengl/qopenglfunctions.h3
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp69
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp11
-rw-r--r--src/gui/painting/qcolor.cpp5
-rw-r--r--src/gui/painting/qdrawhelper.cpp841
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp56
-rw-r--r--src/gui/painting/qdrawhelper_p.h30
-rw-r--r--src/gui/painting/qpagedpaintdevice.cpp65
-rw-r--r--src/gui/painting/qpagedpaintdevice.h6
-rw-r--r--src/gui/painting/qpagedpaintdevice_p.h40
-rw-r--r--src/gui/painting/qpdfwriter.cpp27
-rw-r--r--src/gui/text/qcssparser.cpp7
-rw-r--r--src/gui/text/qtextdocument.cpp15
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp36
-rw-r--r--src/gui/text/qtextdocumentfragment_p.h1
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp20
-rw-r--r--src/gui/text/qtextengine.cpp89
-rw-r--r--src/gui/text/qtextengine_p.h8
-rw-r--r--src/gui/text/qtextformat.cpp32
-rw-r--r--src/gui/text/qtextformat.h6
-rw-r--r--src/gui/text/qtexthtmlparser.cpp7
-rw-r--r--src/gui/text/qtextlayout.cpp25
-rw-r--r--src/gui/text/qtextoption.cpp3
53 files changed, 1426 insertions, 1161 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index d60a21606b..6b48f573b2 100644
--- a/src/gui/accessible/qaccessible.cpp
+++ b/src/gui/accessible/qaccessible.cpp
@@ -202,7 +202,7 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
This enum type defines accessible event types.
- \omitvalue InvalidEvent Internal: Used when creating subclasses of QAccessibleEvent.
+ \omitvalue InvalidEvent \omit Internal: Used when creating subclasses of QAccessibleEvent. \endomit
\value AcceleratorChanged The keyboard accelerator for an action has been changed.
\value ActionChanged An action has been changed.
\value ActiveDescendantChanged
@@ -273,27 +273,27 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\value SelectionWithin Several changes to a selection has occurred in an item
view.
\value SoundPlayed A sound has been played by an object
- \omitvalue StateChanged The QAccessible::State of an object has changed.
- This value is used internally for the QAccessibleStateChangeEvent.
+ \omitvalue StateChanged \omit The QAccessible::State of an object has changed.
+ This value is used internally for the QAccessibleStateChangeEvent. \endomit
\value TableCaptionChanged A table caption has been changed.
\value TableColumnDescriptionChanged The description of a table column, typically found in
the column's header, has been changed.
\value TableColumnHeaderChanged A table column header has been changed.
- \omitvalue TableModelChanged The model providing data for a table has been changed.
+ \omitvalue TableModelChanged \omit The model providing data for a table has been changed. \endomit
\value TableRowDescriptionChanged The description of a table row, typically found in the
row's header, has been changed.
\value TableRowHeaderChanged A table row header has been changed.
\value TableSummaryChanged The summary of a table has been changed.
\omitvalue TextAttributeChanged
- \omitvalue TextCaretMoved The caret has moved in an editable widget.
+ \omitvalue TextCaretMoved \omit The caret has moved in an editable widget.
The caret represents the cursor position in an editable
- widget with the input focus.
+ widget with the input focus. \endomit
\value TextColumnChanged A text column has been changed.
- \omitvalue TextInserted Text has been inserted into an editable widget.
- \omitvalue TextRemoved Text has been removed from an editable widget.
- \omitvalue TextSelectionChanged The selected text has changed in an editable widget.
- \omitvalue TextUpdated The text has been update in an editable widget.
- \omitvalue ValueChanged The QAccessible::Value of an object has changed.
+ \omitvalue TextInserted \omit Text has been inserted into an editable widget. \endomit
+ \omitvalue TextRemoved \omit Text has been removed from an editable widget. \endomit
+ \omitvalue TextSelectionChanged \omit The selected text has changed in an editable widget. \endomit
+ \omitvalue TextUpdated \omit The text has been update in an editable widget. \endomit
+ \omitvalue ValueChanged \omit The QAccessible::Value of an object has changed. \endomit
\value VisibleDataChanged
The values for this enum are defined to be the same as those defined in the
@@ -441,10 +441,10 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\note When subclassing one of these interfaces, \l QAccessibleInterface::interface_cast() needs to be implemented.
\value TextInterface For text that supports selections or is more than one line. Simple labels do not need to implement this interface.
- \omitvalue EditableTextInterface For text that can be edited by the user.
+ \omitvalue EditableTextInterface \omit For text that can be edited by the user. \endomit
\value ValueInterface For objects that are used to manipulate a value, for example slider or scroll bar.
\value ActionInterface For interactive objects that allow the user to trigger an action. Basically everything that allows for example mouse interaction.
- \omitvalue ImageInterface For objects that represent an image. This interface is generally less important.
+ \omitvalue ImageInterface \omit For objects that represent an image. This interface is generally less important. \endomit
\value TableInterface For lists, tables and trees.
\value TableCellInterface For cells in a TableInterface object.
diff --git a/src/gui/configure.json b/src/gui/configure.json
index 220662ea8e..40a91d261b 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -44,7 +44,7 @@
"xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] },
"xcb-native-painting": "boolean",
"xcb-xlib": "boolean",
- "xinput2": "boolean",
+ "xcb-xinput": "boolean",
"xkb": "boolean",
"xkbcommon": { "type": "enum", "values": [ "no", "qt", "system" ] },
"xkbcommon-evdev": "boolean",
@@ -439,18 +439,18 @@
]
},
"xcb": {
- "label": "XCB >= 1.5 (core)",
+ "label": "XCB >= 1.9 (core)",
"test": {
"include": "xcb/xcb.h",
"main": [
"int primaryScreen = 0;",
"(void)xcb_connect(\"\", &primaryScreen);",
- "// This won't compile unless libxcb >= 1.5 which defines XCB_ATOM_PRIMARY.",
- "int xcbAtomPrimary = XCB_ATOM_PRIMARY;"
+ "// This won't compile unless libxcb >= 1.9 which defines XCB_CONN_CLOSED_INVALID_SCREEN.",
+ "int xcbScreenError = XCB_CONN_CLOSED_INVALID_SCREEN;"
]
},
"sources": [
- { "type": "pkgConfig", "args": "xcb >= 1.5" },
+ { "type": "pkgConfig", "args": "xcb >= 1.9" },
"-lxcb"
]
},
@@ -566,33 +566,22 @@
"-lxcb-glx -lxcb"
]
},
- "xinput2": {
- "label": "Xinput2",
+ "xcb_xinput": {
+ "label": "XCB XInput",
"test": {
- "include": [ "X11/Xlib.h", "X11/extensions/XInput2.h", "X11/extensions/Xge.h" ],
- "tail": [
- "#ifndef XInput_2_0",
- "# error Missing XInput_2_0 #define",
- "#endif"
- ],
+ "include": [ "xcb/xcb.h", "xcb/xinput.h" ],
"main": [
- "// need XGenericEventCookie for XInput2 to work",
- "Display *dpy = 0;",
- "XEvent xevent;",
- "XIEvent *xievent = 0;",
- "XIDeviceEvent *xideviceevent = 0;",
- "XIHierarchyEvent *xihierarchyevent = 0;",
- "int deviceid = 0;",
- "int len = 0;",
- "(void) XGetEventData(dpy, &xevent.xcookie);",
- "XFreeEventData(dpy, &xevent.xcookie);",
- "(void) XIListProperties(dpy, deviceid, &len);"
- ],
- "qmake": "CONFIG += x11"
+ "int primaryScreen = 0;",
+ "xcb_connection_t *connection = xcb_connect(\"\", &primaryScreen);",
+ "xcb_generic_error_t *error = 0;",
+ "xcb_input_xi_query_version_cookie_t xinput_query_cookie = xcb_input_xi_query_version(",
+ " connection, XCB_INPUT_MAJOR_VERSION, XCB_INPUT_MINOR_VERSION);",
+ "xcb_input_xi_query_version_reply(connection, xinput_query_cookie, &error);"
+ ]
},
"sources": [
- { "type": "pkgConfig", "args": "xi" },
- "-lXi"
+ { "type": "pkgConfig", "args": "xcb-xinput >= 1.12 xcb" },
+ "-lxcb-xinput -lxcb"
]
},
"xkbcommon": {
@@ -661,6 +650,26 @@
"fxc.exe"
]
},
+ "drm_atomic": {
+ "label": "DRM Atomic API",
+ "type": "compile",
+ "test": {
+ "head": [
+ "#include <stdlib.h>",
+ "#include <stdint.h>",
+ "extern \"C\" {"
+ ],
+ "include": [
+ "xf86drmMode.h",
+ "xf86drm.h"
+ ],
+ "tail": [
+ "}"
+ ],
+ "main": "drmModeAtomicReq *request;"
+ },
+ "use": "drm"
+ },
"egl-x11": {
"label": "EGL on X11",
"type": "compile",
@@ -1010,6 +1019,11 @@
"condition": "libs.drm",
"output": [ "publicQtConfig", "privateFeature" ]
},
+ "drm_atomic": {
+ "label": "DRM Atomic API",
+ "condition": "libs.drm && tests.drm_atomic",
+ "output": [ "privateFeature" ]
+ },
"libinput": {
"label": "libinput",
"condition": "features.libudev && libs.libinput",
@@ -1327,10 +1341,10 @@
"condition": "features.sessionmanager && libs.x11sm",
"output": [ "privateFeature" ]
},
- "xinput2": {
- "label": "Xinput2",
+ "xcb-xinput": {
+ "label": "XCB XInput",
"emitIf": "features.xcb",
- "condition": "features.xcb-xlib && libs.xinput2",
+ "condition": "!features.system-xcb || libs.xcb_xinput",
"output": [ "privateFeature" ]
},
"xkbcommon-evdev": {
@@ -1701,7 +1715,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"section": "X11",
"condition": "features.xcb",
"entries": [
- "system-xcb", "egl_x11", "xinput2", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xlib", "xkbcommon-system", "xcb-native-painting"
+ "system-xcb", "egl_x11", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xinput", "xcb-xlib", "xkbcommon-system", "xcb-native-painting"
]
},
{
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 76aba944b2..b4942f06d4 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -9,6 +9,7 @@ HEADERS += \
image/qimage_p.h \
image/qimageiohandler.h \
image/qimagereader.h \
+ image/qimagereaderwriterhelpers_p.h \
image/qimagewriter.h \
image/qpaintengine_pic_p.h \
image/qpicture.h \
@@ -33,6 +34,7 @@ SOURCES += \
image/qimage_conversions.cpp \
image/qimageiohandler.cpp \
image/qimagereader.cpp \
+ image/qimagereaderwriterhelpers.cpp \
image/qimagewriter.cpp \
image/qpaintengine_pic.cpp \
image/qpicture.cpp \
diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp
index e8405a6d11..2453242fa8 100644
--- a/src/gui/image/qbitmap.cpp
+++ b/src/gui/image/qbitmap.cpp
@@ -189,9 +189,7 @@ QBitmap &QBitmap::operator=(const QPixmap &pixmap)
} else if (pixmap.depth() == 1) { // 1-bit pixmap
QPixmap::operator=(pixmap); // shallow assignment
} else { // n-bit depth pixmap
- QImage image;
- image = pixmap.toImage(); // convert pixmap to image
- *this = fromImage(image); // will dither image
+ *this = fromImage(pixmap.toImage()); // will dither image
}
return *this;
}
@@ -223,6 +221,24 @@ QBitmap::operator QVariant() const
return QVariant(QVariant::Bitmap, this);
}
+static QBitmap makeBitmap(QImage &&image, Qt::ImageConversionFlags flags)
+{
+ // make sure image.color(0) == Qt::color0 (white)
+ // and image.color(1) == Qt::color1 (black)
+ const QRgb c0 = QColor(Qt::black).rgb();
+ const QRgb c1 = QColor(Qt::white).rgb();
+ if (image.color(0) == c0 && image.color(1) == c1) {
+ image.invertPixels();
+ image.setColor(0, c1);
+ image.setColor(1, c0);
+ }
+
+ QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::BitmapType));
+
+ data->fromImageInPlace(image, flags | Qt::MonoOnly);
+ return QPixmap(data.take());
+}
+
/*!
Returns a copy of the given \a image converted to a bitmap using
the specified image conversion \a flags.
@@ -234,22 +250,24 @@ QBitmap QBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
if (image.isNull())
return QBitmap();
- QImage img = image.convertToFormat(QImage::Format_MonoLSB, flags);
+ return makeBitmap(image.convertToFormat(QImage::Format_MonoLSB, flags), flags);
+}
- // make sure image.color(0) == Qt::color0 (white)
- // and image.color(1) == Qt::color1 (black)
- const QRgb c0 = QColor(Qt::black).rgb();
- const QRgb c1 = QColor(Qt::white).rgb();
- if (img.color(0) == c0 && img.color(1) == c1) {
- img.invertPixels();
- img.setColor(0, c1);
- img.setColor(1, c0);
- }
+/*!
+ \since 5.12
+ \overload
- QScopedPointer<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::BitmapType));
+ Returns a copy of the given \a image converted to a bitmap using
+ the specified image conversion \a flags.
- data->fromImage(img, flags | Qt::MonoOnly);
- return QPixmap(data.take());
+ \sa fromData()
+*/
+QBitmap QBitmap::fromImage(QImage &&image, Qt::ImageConversionFlags flags)
+{
+ if (image.isNull())
+ return QBitmap();
+
+ return makeBitmap(std::move(image).convertToFormat(QImage::Format_MonoLSB, flags), flags);
}
/*!
@@ -277,7 +295,7 @@ QBitmap QBitmap::fromData(const QSize &size, const uchar *bits, QImage::Format m
int bytesPerLine = (size.width() + 7) / 8;
for (int y = 0; y < size.height(); ++y)
memcpy(image.scanLine(y), bits + bytesPerLine * y, bytesPerLine);
- return QBitmap::fromImage(image);
+ return QBitmap::fromImage(std::move(image));
}
/*!
diff --git a/src/gui/image/qbitmap.h b/src/gui/image/qbitmap.h
index 6a8c8b3457..188064fccf 100644
--- a/src/gui/image/qbitmap.h
+++ b/src/gui/image/qbitmap.h
@@ -72,6 +72,7 @@ public:
inline void clear() { fill(Qt::color0); }
static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor);
+ static QBitmap fromImage(QImage &&image, Qt::ImageConversionFlags flags = Qt::AutoColor);
static QBitmap fromData(const QSize &size, const uchar *bits,
QImage::Format monoFormat = QImage::Format_MonoLSB);
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 7fcae12cbd..e1cac2011d 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -2582,15 +2582,14 @@ bool QImage::allGray() const
break;
}
- const int buffer_size = 2048;
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
const QPixelLayout *layout = &qPixelLayouts[d->format];
FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
for (int j = 0; j < d->height; ++j) {
const uchar *b = constScanLine(j);
int x = 0;
while (x < d->width) {
- int l = qMin(d->width - x, buffer_size);
+ int l = qMin(d->width - x, BufferSize);
const uint *ptr = fetch(buffer, b, x, l);
ptr = layout->convertToARGB32PM(buffer, ptr, l, 0, 0);
for (int i = 0; i < l; ++i) {
@@ -3210,31 +3209,27 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical)
inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
{
- Q_ASSERT(layout->redWidth == layout->blueWidth);
FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
StorePixelsFunc store = qStorePixels[layout->bpp];
+ RbSwapFunc func = layout->rbSwap;
+ if (!func) {
+ qWarning("Trying to rb-swap an image format where it doesn't make sense");
+ if (src != dst)
+ *dst = *src;
+ return;
+ }
- const uint redBlueMask = (1 << layout->redWidth) - 1;
- const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
- | (((1 << layout->greenWidth) - 1) << layout->greenShift);
-
- const int buffer_size = 2048;
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
for (int i = 0; i < height; ++i) {
uchar *q = dst->scanLine(i);
const uchar *p = src->constScanLine(i);
int x = 0;
while (x < width) {
- int l = qMin(width - x, buffer_size);
+ int l = qMin(width - x, BufferSize);
const uint *ptr = fetch(buffer, p, x, l);
- for (int j = 0; j < l; ++j) {
- uint red = (ptr[j] >> layout->redShift) & redBlueMask;
- uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
- buffer[j] = (ptr[j] & alphaGreenMask)
- | (red << layout->blueShift)
- | (blue << layout->redShift);
- }
- store(q, buffer, x, l);
+ ptr = func(buffer, ptr, l);
+ if (q != (const uchar *)ptr)
+ store(q, ptr, x, l);
x += l;
}
}
@@ -3321,23 +3316,6 @@ QImage QImage::rgbSwapped_helper() const
}
}
break;
- case Format_BGR30:
- case Format_A2BGR30_Premultiplied:
- case Format_RGB30:
- case Format_A2RGB30_Premultiplied:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- uint *q = (uint*)res.scanLine(i);
- const uint *p = (const uint*)constScanLine(i);
- const uint *end = p + d->width;
- while (p < end) {
- *q = qRgbSwapRgb30(*p);
- p++;
- q++;
- }
- }
- break;
default:
res = QImage(d->width, d->height, d->format);
rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
@@ -3457,8 +3435,7 @@ void QImage::rgbSwapped_inplace()
bool QImage::load(const QString &fileName, const char* format)
{
- QImage image = QImageReader(fileName, format).read();
- operator=(image);
+ *this = QImageReader(fileName, format).read();
return !isNull();
}
@@ -3471,8 +3448,7 @@ bool QImage::load(const QString &fileName, const char* format)
bool QImage::load(QIODevice* device, const char* format)
{
- QImage image = QImageReader(device, format).read();
- operator=(image);
+ *this = QImageReader(device, format).read();
return !isNull();
}
@@ -3492,8 +3468,7 @@ bool QImage::load(QIODevice* device, const char* format)
bool QImage::loadFromData(const uchar *data, int len, const char *format)
{
- QImage image = fromData(data, len, format);
- operator=(image);
+ *this = fromData(data, len, format);
return !isNull();
}
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 4eef617336..39d97f4bd9 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -145,8 +145,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
// Cannot be used with indexed formats.
Q_ASSERT(dest->format > QImage::Format_Indexed8);
Q_ASSERT(src->format > QImage::Format_Indexed8);
- const int buffer_size = 2048;
- uint buf[buffer_size];
+ uint buf[BufferSize];
uint *buffer = buf;
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
@@ -157,7 +156,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
const StorePixelsFunc store = qStorePixels[destLayout->bpp];
ConvertFunc convertToARGB32PM = srcLayout->convertToARGB32PM;
ConvertFunc convertFromARGB32PM = destLayout->convertFromARGB32PM;
- if (srcLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ if (!srcLayout->hasAlphaChannel && destLayout->convertFromRGB32) {
// If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method.
convertFromARGB32PM = destLayout->convertFromRGB32;
} else {
@@ -174,7 +173,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
}
}
if ((src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888) &&
- destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ !destLayout->hasAlphaChannel && destLayout->convertFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
convertToARGB32PM = qPixelLayouts[src->format + 1].convertToARGB32PM;
if (dest->format == QImage::Format_RGB32)
@@ -196,7 +195,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
if (destLayout->bpp == QPixelLayout::BPP32)
buffer = reinterpret_cast<uint *>(destData) + x;
else
- l = qMin(l, buffer_size);
+ l = qMin(l, BufferSize);
const uint *ptr = fetch(buffer, srcData, x, l);
ptr = convertToARGB32PM(buffer, ptr, l, 0, ditherPtr);
ptr = convertFromARGB32PM(buffer, ptr, l, 0, ditherPtr);
@@ -217,8 +216,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
if (data->depth != qt_depthForFormat(dst_format))
return false;
- const int buffer_size = 2048;
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
uchar *srcData = data->data;
@@ -227,7 +225,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
const StorePixelsFunc store = qStorePixels[destLayout->bpp];
ConvertFunc convertToARGB32PM = srcLayout->convertToARGB32PM;
ConvertFunc convertFromARGB32PM = destLayout->convertFromARGB32PM;
- if (srcLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ if (!srcLayout->hasAlphaChannel && destLayout->convertFromRGB32) {
// If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method.
convertFromARGB32PM = destLayout->convertFromRGB32;
} else {
@@ -243,7 +241,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
}
}
if ((data->format == QImage::Format_ARGB32 || data->format == QImage::Format_RGBA8888) &&
- destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ !destLayout->hasAlphaChannel && destLayout->convertFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
convertToARGB32PM = qPixelLayouts[data->format + 1].convertToARGB32PM;
if (dst_format == QImage::Format_RGB32)
@@ -261,7 +259,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
int x = 0;
while (x < data->width) {
dither.x = x;
- int l = qMin(data->width - x, buffer_size);
+ int l = qMin(data->width - x, BufferSize);
const uint *ptr = fetch(buffer, srcData, x, l);
ptr = convertToARGB32PM(buffer, ptr, l, 0, ditherPtr);
ptr = convertFromARGB32PM(buffer, ptr, l, 0, ditherPtr);
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 7086e102ea..6d358984d6 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -164,73 +164,13 @@
#include <private/qpnghandler_p.h>
#endif
+#include <private/qimagereaderwriterhelpers_p.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_IMAGEFORMATPLUGIN
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
-#endif
-
-enum _qt_BuiltInFormatType {
-#ifndef QT_NO_IMAGEFORMAT_PNG
- _qt_PngFormat,
-#endif
-#ifndef QT_NO_IMAGEFORMAT_BMP
- _qt_BmpFormat,
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PPM
- _qt_PpmFormat,
- _qt_PgmFormat,
- _qt_PbmFormat,
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XBM
- _qt_XbmFormat,
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XPM
- _qt_XpmFormat,
-#endif
- _qt_NumFormats,
- _qt_NoFormat = -1
-};
-
-#if !defined(QT_NO_IMAGEFORMAT_PPM)
-# define MAX_MT_SIZE 20
-#elif !defined(QT_NO_IMAGEFORMAT_XBM) || !defined(QT_NO_IMAGEFORMAT_XPM)
-# define MAX_MT_SIZE 10
-#else
-# define MAX_MT_SIZE 4
-#endif
-
-struct _qt_BuiltInFormatStruct
-{
- char extension[4];
- char mimeType[MAX_MT_SIZE];
-};
-
-#undef MAX_MT_SIZE
-
-static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
-#ifndef QT_NO_IMAGEFORMAT_PNG
- {"png", "png"},
-#endif
-#ifndef QT_NO_IMAGEFORMAT_BMP
- {"bmp", "bmp"},
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PPM
- {"ppm", "x-portable-pixmap"},
- {"pgm", "x-portable-graymap"},
- {"pbm", "x-portable-bitmap"},
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XBM
- {"xbm", "x-xbitmap"},
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XPM
- {"xpm", "x-xpixmap"},
-#endif
-};
-Q_STATIC_ASSERT(_qt_NumFormats == sizeof _qt_BuiltInFormats / sizeof *_qt_BuiltInFormats);
+using namespace QImageReaderWriterHelpers;
static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
const QByteArray &format,
@@ -251,7 +191,7 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
typedef QMultiMap<int, QString> PluginKeyMap;
// check if we have plugins that support the image format
- QFactoryLoader *l = loader();
+ auto l = QImageReaderWriterHelpers::pluginLoader();
const PluginKeyMap keyMap = l->keyMap();
#ifdef QIMAGEREADER_DEBUG
@@ -1565,16 +1505,6 @@ QByteArray QImageReader::imageFormat(QIODevice *device)
return format;
}
-#ifndef QT_NO_IMAGEFORMATPLUGIN
-void supportedImageHandlerFormats(QFactoryLoader *loader,
- QImageIOPlugin::Capability cap,
- QList<QByteArray> *result);
-
-void supportedImageHandlerMimeTypes(QFactoryLoader *loader,
- QImageIOPlugin::Capability cap,
- QList<QByteArray> *result);
-#endif
-
/*!
Returns the list of image formats supported by QImageReader.
@@ -1605,18 +1535,7 @@ void supportedImageHandlerMimeTypes(QFactoryLoader *loader,
QList<QByteArray> QImageReader::supportedImageFormats()
{
- QList<QByteArray> formats;
- formats.reserve(_qt_NumFormats);
- for (int i = 0; i < _qt_NumFormats; ++i)
- formats << _qt_BuiltInFormats[i].extension;
-
-#ifndef QT_NO_IMAGEFORMATPLUGIN
- supportedImageHandlerFormats(loader(), QImageIOPlugin::CanRead, &formats);
-#endif // QT_NO_IMAGEFORMATPLUGIN
-
- std::sort(formats.begin(), formats.end());
- formats.erase(std::unique(formats.begin(), formats.end()), formats.end());
- return formats;
+ return QImageReaderWriterHelpers::supportedImageFormats(QImageReaderWriterHelpers::CanRead);
}
/*!
@@ -1630,18 +1549,24 @@ QList<QByteArray> QImageReader::supportedImageFormats()
QList<QByteArray> QImageReader::supportedMimeTypes()
{
- QList<QByteArray> mimeTypes;
- mimeTypes.reserve(_qt_NumFormats);
- for (const auto &fmt : _qt_BuiltInFormats)
- mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType);
+ return QImageReaderWriterHelpers::supportedMimeTypes(QImageReaderWriterHelpers::CanRead);
+}
-#ifndef QT_NO_IMAGEFORMATPLUGIN
- supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanRead, &mimeTypes);
-#endif // QT_NO_IMAGEFORMATPLUGIN
+/*!
+ \since 5.12
- std::sort(mimeTypes.begin(), mimeTypes.end());
- mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end());
- return mimeTypes;
+ Returns the list of image formats corresponding to \a mimeType.
+
+ Note that the QGuiApplication instance must be created before this function is
+ called.
+
+ \sa supportedImageFormats(), supportedMimeTypes()
+*/
+
+QList<QByteArray> QImageReader::imageFormatsForMimeType(const QByteArray &mimeType)
+{
+ return QImageReaderWriterHelpers::imageFormatsForMimeType(mimeType,
+ QImageReaderWriterHelpers::CanRead);
}
QT_END_NAMESPACE
diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h
index 9d6c1e0b1e..4e9a08b6e6 100644
--- a/src/gui/image/qimagereader.h
+++ b/src/gui/image/qimagereader.h
@@ -144,6 +144,7 @@ public:
static QByteArray imageFormat(QIODevice *device);
static QList<QByteArray> supportedImageFormats();
static QList<QByteArray> supportedMimeTypes();
+ static QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType);
private:
Q_DISABLE_COPY(QImageReader)
diff --git a/src/gui/image/qimagereaderwriterhelpers.cpp b/src/gui/image/qimagereaderwriterhelpers.cpp
new file mode 100644
index 0000000000..a5b7fb6449
--- /dev/null
+++ b/src/gui/image/qimagereaderwriterhelpers.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "private/qimagereaderwriterhelpers_p.h"
+
+#include <qjsonarray.h>
+#include <qmutex.h>
+#include <private/qfactoryloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QImageReaderWriterHelpers {
+
+#ifndef QT_NO_IMAGEFORMATPLUGIN
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
+Q_GLOBAL_STATIC(QMutex, loaderMutex)
+
+static void appendImagePluginFormats(QFactoryLoader *loader,
+ QImageIOPlugin::Capability cap,
+ QList<QByteArray> *result)
+{
+ typedef QMultiMap<int, QString> PluginKeyMap;
+ typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
+
+ const PluginKeyMap keyMap = loader->keyMap();
+ const PluginKeyMapConstIterator cend = keyMap.constEnd();
+ int i = -1;
+ QImageIOPlugin *plugin = 0;
+ result->reserve(result->size() + keyMap.size());
+ for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) {
+ if (it.key() != i) {
+ i = it.key();
+ plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
+ }
+ const QByteArray key = it.value().toLatin1();
+ if (plugin && (plugin->capabilities(0, key) & cap) != 0)
+ result->append(key);
+ }
+}
+
+static void appendImagePluginMimeTypes(QFactoryLoader *loader,
+ QImageIOPlugin::Capability cap,
+ QList<QByteArray> *result,
+ QList<QByteArray> *resultKeys = nullptr)
+{
+ QList<QJsonObject> metaDataList = loader->metaData();
+
+ const int pluginCount = metaDataList.size();
+ for (int i = 0; i < pluginCount; ++i) {
+ const QJsonObject metaData = metaDataList.at(i).value(QLatin1String("MetaData")).toObject();
+ const QJsonArray keys = metaData.value(QLatin1String("Keys")).toArray();
+ const QJsonArray mimeTypes = metaData.value(QLatin1String("MimeTypes")).toArray();
+ QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
+ const int keyCount = keys.size();
+ for (int k = 0; k < keyCount; ++k) {
+ const QByteArray key = keys.at(k).toString().toLatin1();
+ if (plugin && (plugin->capabilities(0, key) & cap) != 0) {
+ result->append(mimeTypes.at(k).toString().toLatin1());
+ if (resultKeys)
+ resultKeys->append(key);
+ }
+ }
+ }
+}
+
+QSharedPointer<QFactoryLoader> pluginLoader()
+{
+ loaderMutex()->lock();
+ return QSharedPointer<QFactoryLoader>(loader(), [](QFactoryLoader *) {
+ loaderMutex()->unlock();
+ });
+}
+
+static inline QImageIOPlugin::Capability pluginCapability(Capability cap)
+{
+ return cap == CanRead ? QImageIOPlugin::CanRead : QImageIOPlugin::CanWrite;
+}
+
+#endif // QT_NO_IMAGEFORMATPLUGIN
+
+QList<QByteArray> supportedImageFormats(Capability cap)
+{
+ QList<QByteArray> formats;
+ formats.reserve(_qt_NumFormats);
+ for (int i = 0; i < _qt_NumFormats; ++i)
+ formats << _qt_BuiltInFormats[i].extension;
+
+#ifndef QT_NO_IMAGEFORMATPLUGIN
+ appendImagePluginFormats(loader(), pluginCapability(cap), &formats);
+#endif // QT_NO_IMAGEFORMATPLUGIN
+
+ std::sort(formats.begin(), formats.end());
+ formats.erase(std::unique(formats.begin(), formats.end()), formats.end());
+ return formats;
+}
+
+QList<QByteArray> supportedMimeTypes(Capability cap)
+{
+ QList<QByteArray> mimeTypes;
+ mimeTypes.reserve(_qt_NumFormats);
+ for (const auto &fmt : _qt_BuiltInFormats)
+ mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType);
+
+#ifndef QT_NO_IMAGEFORMATPLUGIN
+ appendImagePluginMimeTypes(loader(), pluginCapability(cap), &mimeTypes);
+#endif // QT_NO_IMAGEFORMATPLUGIN
+
+ std::sort(mimeTypes.begin(), mimeTypes.end());
+ mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end());
+ return mimeTypes;
+}
+
+QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap)
+{
+ QList<QByteArray> formats;
+ if (mimeType.startsWith("image/")) {
+ const QByteArray type = mimeType.mid(sizeof("image/") - 1);
+ for (const auto &fmt : _qt_BuiltInFormats) {
+ if (fmt.mimeType == type && !formats.contains(fmt.extension))
+ formats << fmt.extension;
+ }
+ }
+
+#ifndef QT_NO_IMAGEFORMATPLUGIN
+ QList<QByteArray> mimeTypes;
+ QList<QByteArray> keys;
+ appendImagePluginMimeTypes(loader(), pluginCapability(cap), &mimeTypes, &keys);
+ for (int i = 0; i < mimeTypes.size(); ++i) {
+ if (mimeTypes.at(i) == mimeType) {
+ const auto &key = keys.at(i);
+ if (!formats.contains(key))
+ formats << key;
+ }
+ }
+#endif // QT_NO_IMAGEFORMATPLUGIN
+
+ return formats;
+}
+
+} // QImageReaderWriterHelpers
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qimagereaderwriterhelpers_p.h b/src/gui/image/qimagereaderwriterhelpers_p.h
new file mode 100644
index 0000000000..6fe418a8ab
--- /dev/null
+++ b/src/gui/image/qimagereaderwriterhelpers_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QIMAGEREADERWRITERHELPERS_P_H
+#define QIMAGEREADERWRITERHELPERS_P_H
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <qsharedpointer.h>
+#include "qimageiohandler.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QFactoryLoader;
+
+namespace QImageReaderWriterHelpers {
+
+enum _qt_BuiltInFormatType {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ _qt_PngFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ _qt_BmpFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ _qt_PpmFormat,
+ _qt_PgmFormat,
+ _qt_PbmFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ _qt_XbmFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ _qt_XpmFormat,
+#endif
+ _qt_NumFormats,
+ _qt_NoFormat = -1
+};
+
+#if !defined(QT_NO_IMAGEFORMAT_PPM)
+# define MAX_MT_SIZE 20
+#elif !defined(QT_NO_IMAGEFORMAT_XBM) || !defined(QT_NO_IMAGEFORMAT_XPM)
+# define MAX_MT_SIZE 10
+#else
+# define MAX_MT_SIZE 4
+#endif
+
+struct _qt_BuiltInFormatStruct
+{
+ char extension[4];
+ char mimeType[MAX_MT_SIZE];
+};
+
+#undef MAX_MT_SIZE
+
+static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ {"png", "png"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_BMP
+ {"bmp", "bmp"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PPM
+ {"ppm", "x-portable-pixmap"},
+ {"pgm", "x-portable-graymap"},
+ {"pbm", "x-portable-bitmap"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XBM
+ {"xbm", "x-xbitmap"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ {"xpm", "x-xpixmap"},
+#endif
+};
+Q_STATIC_ASSERT(_qt_NumFormats == sizeof _qt_BuiltInFormats / sizeof *_qt_BuiltInFormats);
+
+#ifndef QT_NO_IMAGEFORMATPLUGIN
+QSharedPointer<QFactoryLoader> pluginLoader();
+#endif
+
+enum Capability {
+ CanRead,
+ CanWrite
+};
+QList<QByteArray> supportedImageFormats(Capability cap);
+QList<QByteArray> supportedMimeTypes(Capability cap);
+QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap);
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QIMAGEREADERWRITERHELPERS_P_H
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index a39d204677..62eeb74727 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -102,7 +102,6 @@
#include <qfileinfo.h>
#include <qimage.h>
#include <qimageiohandler.h>
-#include <qjsonarray.h>
#include <qset.h>
#include <qvariant.h>
@@ -119,15 +118,12 @@
#include <private/qpnghandler_p.h>
#endif
+#include <private/qimagereaderwriterhelpers_p.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_IMAGEFORMATPLUGIN
-Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
- (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
-#endif
-
static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
const QByteArray &format)
{
@@ -139,7 +135,7 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
typedef QMultiMap<int, QString> PluginKeyMap;
// check if any plugins can write the image
- QFactoryLoader *l = loader();
+ auto l = QImageReaderWriterHelpers::pluginLoader();
const PluginKeyMap keyMap = l->keyMap();
int suffixPluginIndex = -1;
#endif
@@ -824,52 +820,6 @@ bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
return d->handler->supportsOption(option);
}
-
-#ifndef QT_NO_IMAGEFORMATPLUGIN
-void supportedImageHandlerFormats(QFactoryLoader *loader,
- QImageIOPlugin::Capability cap,
- QList<QByteArray> *result)
-{
- typedef QMultiMap<int, QString> PluginKeyMap;
- typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
-
- const PluginKeyMap keyMap = loader->keyMap();
- const PluginKeyMapConstIterator cend = keyMap.constEnd();
- int i = -1;
- QImageIOPlugin *plugin = 0;
- result->reserve(result->size() + keyMap.size());
- for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) {
- if (it.key() != i) {
- i = it.key();
- plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
- }
- const QByteArray key = it.value().toLatin1();
- if (plugin && (plugin->capabilities(0, key) & cap) != 0)
- result->append(key);
- }
-}
-
-void supportedImageHandlerMimeTypes(QFactoryLoader *loader,
- QImageIOPlugin::Capability cap,
- QList<QByteArray> *result)
-{
- QList<QJsonObject> metaDataList = loader->metaData();
-
- const int pluginCount = metaDataList.size();
- for (int i = 0; i < pluginCount; ++i) {
- const QJsonObject metaData = metaDataList.at(i).value(QLatin1String("MetaData")).toObject();
- const QJsonArray keys = metaData.value(QLatin1String("Keys")).toArray();
- const QJsonArray mimeTypes = metaData.value(QLatin1String("MimeTypes")).toArray();
- QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(loader->instance(i));
- const int keyCount = keys.size();
- for (int k = 0; k < keyCount; ++k) {
- if (plugin && (plugin->capabilities(0, keys.at(k).toString().toLatin1()) & cap) != 0)
- result->append(mimeTypes.at(k).toString().toLatin1());
- }
- }
-}
-#endif // QT_NO_IMAGEFORMATPLUGIN
-
/*!
Returns the list of image formats supported by QImageWriter.
@@ -897,30 +847,7 @@ void supportedImageHandlerMimeTypes(QFactoryLoader *loader,
*/
QList<QByteArray> QImageWriter::supportedImageFormats()
{
- QList<QByteArray> formats;
-#ifndef QT_NO_IMAGEFORMAT_BMP
- formats << "bmp";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PPM
- formats << "pbm" << "pgm" << "ppm";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XBM
- formats << "xbm";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XPM
- formats << "xpm";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PNG
- formats << "png";
-#endif
-
-#ifndef QT_NO_IMAGEFORMATPLUGIN
- supportedImageHandlerFormats(loader(), QImageIOPlugin::CanWrite, &formats);
-#endif // QT_NO_IMAGEFORMATPLUGIN
-
- std::sort(formats.begin(), formats.end());
- formats.erase(std::unique(formats.begin(), formats.end()), formats.end());
- return formats;
+ return QImageReaderWriterHelpers::supportedImageFormats(QImageReaderWriterHelpers::CanWrite);
}
/*!
@@ -933,32 +860,24 @@ QList<QByteArray> QImageWriter::supportedImageFormats()
*/
QList<QByteArray> QImageWriter::supportedMimeTypes()
{
- QList<QByteArray> mimeTypes;
-#ifndef QT_NO_IMAGEFORMAT_BMP
- mimeTypes << "image/bmp";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PPM
- mimeTypes << "image/x-portable-bitmap";
- mimeTypes << "image/x-portable-graymap";
- mimeTypes << "image/x-portable-pixmap";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XBM
- mimeTypes << "image/x-xbitmap";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_XPM
- mimeTypes << "image/x-xpixmap";
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PNG
- mimeTypes << "image/png";
-#endif
+ return QImageReaderWriterHelpers::supportedMimeTypes(QImageReaderWriterHelpers::CanWrite);
+}
-#ifndef QT_NO_IMAGEFORMATPLUGIN
- supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanWrite, &mimeTypes);
-#endif // QT_NO_IMAGEFORMATPLUGIN
+/*!
+ \since 5.12
- std::sort(mimeTypes.begin(), mimeTypes.end());
- mimeTypes.erase(std::unique(mimeTypes.begin(), mimeTypes.end()), mimeTypes.end());
- return mimeTypes;
+ Returns the list of image formats corresponding to \a mimeType.
+
+ Note that the QGuiApplication instance must be created before this function is
+ called.
+
+ \sa supportedImageFormats(), supportedMimeTypes()
+*/
+
+QList<QByteArray> QImageWriter::imageFormatsForMimeType(const QByteArray &mimeType)
+{
+ return QImageReaderWriterHelpers::imageFormatsForMimeType(mimeType,
+ QImageReaderWriterHelpers::CanWrite);
}
QT_END_NAMESPACE
diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h
index fd1fdd07e8..29c06ccdd2 100644
--- a/src/gui/image/qimagewriter.h
+++ b/src/gui/image/qimagewriter.h
@@ -116,6 +116,7 @@ public:
static QList<QByteArray> supportedImageFormats();
static QList<QByteArray> supportedMimeTypes();
+ static QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType);
private:
Q_DISABLE_COPY(QImageWriter)
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 5b3e3985a7..4cd8befc1b 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -248,9 +248,9 @@ QPixmap::QPixmap(const char * const xpm[])
QImage image(xpm);
if (!image.isNull()) {
if (data && data->pixelType() == QPlatformPixmap::BitmapType)
- *this = QBitmap::fromImage(image);
+ *this = QBitmap::fromImage(std::move(image));
else
- *this = fromImage(image);
+ *this = fromImage(std::move(image));
}
}
#endif
@@ -691,7 +691,7 @@ QBitmap QPixmap::createHeuristicMask(bool clipTight) const
QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode) const
{
QImage image = toImage().convertToFormat(QImage::Format_ARGB32);
- return QBitmap::fromImage(image.createMaskFromColor(maskColor.rgba(), mode));
+ return QBitmap::fromImage(std::move(image).createMaskFromColor(maskColor.rgba(), mode));
}
/*!
@@ -1018,9 +1018,9 @@ QDataStream &operator>>(QDataStream &stream, QPixmap &pixmap)
if (image.isNull()) {
pixmap = QPixmap();
} else if (image.depth() == 1) {
- pixmap = QBitmap::fromImage(image);
+ pixmap = QBitmap::fromImage(std::move(image));
} else {
- pixmap = QPixmap::fromImage(image);
+ pixmap = QPixmap::fromImage(std::move(image));
}
return stream;
}
diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp
index 155a4f88b4..24d86e116d 100644
--- a/src/gui/image/qxbmhandler.cpp
+++ b/src/gui/image/qxbmhandler.cpp
@@ -241,7 +241,7 @@ static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const
}
}
}
-#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifdef Q_CC_MSVC
strcpy_s(p, sizeof(" };\n"), " };\n");
#else
strcpy(p, " };\n");
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 9c54b9ada4..17272ffe69 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -741,10 +741,6 @@ static const struct XPMRGBData {
{ QRGB(139,139, 0), "yellow4" },
{ QRGB(154,205, 50), "yellowgreen" } };
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-inline bool operator<(const XPMRGBData &data1, const XPMRGBData &data2)
-{ return qstrcmp(data1.name, data2.name) < 0; }
-#endif
inline bool operator<(const char *name, const XPMRGBData &data)
{ return qstrcmp(name, data.name) < 0; }
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 50d9bbb2cc..2e2e6b8301 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -960,6 +960,43 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
invertedScrolling(inverted)
{}
+/*!
+ Constructs a wheel event object.
+
+ The \a pos provides the location of the mouse cursor
+ within the window. The position in global coordinates is specified
+ by \a globalPos.
+
+ \a pixelDelta contains the scrolling distance in pixels on screen, while
+ \a angleDelta contains the wheel rotation distance. \a pixelDelta is
+ optional and can be null.
+
+ The mouse and keyboard states at the time of the event are specified by
+ \a buttons and \a modifiers.
+
+ The scrolling phase of the event is specified by \a phase.
+
+ If the wheel event comes from a physical mouse wheel, \a source is set to
+ Qt::MouseEventNotSynthesized. If it comes from a gesture detected by the
+ operating system, or from a non-mouse hardware device, such that \a
+ pixelDelta is directly related to finger movement, \a source is set to
+ Qt::MouseEventSynthesizedBySystem. If it comes from Qt, source would be set
+ to Qt::MouseEventSynthesizedByQt.
+
+ If the system is configured to invert the delta values delivered with the
+ event (such as natural scrolling of the touchpad on macOS), \a inverted
+ should be \c true. Otherwise, \a inverted is \c false
+
+ \sa posF(), globalPosF(), angleDelta(), pixelDelta(), phase()
+*/
+QWheelEvent::QWheelEvent(QPointF pos, QPointF globalPos, QPoint pixelDelta, QPoint angleDelta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase,
+ bool inverted, Qt::MouseEventSource source)
+ : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta),
+ angleD(angleDelta), mouseState(buttons), ph(phase), src(source),
+ invertedScrolling(inverted)
+{}
+
#endif // QT_CONFIG(wheelevent)
/*!
@@ -1533,8 +1570,8 @@ QMoveEvent::~QMoveEvent()
\ingroup events
- Expose events are sent to windows when an area of the window is invalidated
- or window exposure in the windowing system changes.
+ Expose events are sent to windows when an area of the window is invalidated,
+ for example when window exposure in the windowing system changes.
A Window with a client area that is completely covered by another window, or
is otherwise not visible may be considered obscured by Qt and may in such
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index d95da40368..2a47afaa0b 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -193,6 +193,10 @@ public:
QWheelEvent(const QPointF &pos, const QPointF &globalPos, QPoint pixelDelta, QPoint angleDelta,
int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, Qt::MouseEventSource source, bool inverted);
+
+ QWheelEvent(QPointF pos, QPointF globalPos, QPoint pixelDelta, QPoint angleDelta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase,
+ bool inverted, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
~QWheelEvent();
@@ -225,8 +229,8 @@ protected:
QPointF g;
QPoint pixelD;
QPoint angleD;
- int qt4D;
- Qt::Orientation qt4O;
+ int qt4D = 0;
+ Qt::Orientation qt4O = Qt::Vertical;
Qt::MouseButtons mouseState;
uint ph : 2;
uint src: 2;
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index f58dcf17f0..64b703e524 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -150,6 +150,7 @@ public:
MacModelessLayout,
AndroidLayout
};
+ Q_ENUM(ButtonLayout)
QPlatformDialogHelper();
virtual ~QPlatformDialogHelper();
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index a66420c364..bc1aeb8217 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -340,6 +340,20 @@ void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(file
void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); }
/*!
+ Reimplement to let the platform handle non-spontaneous window close.
+
+ When reimplementing make sure to call the base class implementation
+ or QWindowSystemInterface::handleCloseEvent(), which will prompt the
+ user to accept the window close (if needed) and then close the QWindow.
+*/
+bool QPlatformWindow::close()
+{
+ bool accepted = false;
+ QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window(), &accepted);
+ return accepted;
+}
+
+/*!
Reimplement to be able to let Qt raise windows to the top of the desktop
*/
void QPlatformWindow::raise() { qWarning("This plugin does not support raise()"); }
@@ -710,7 +724,7 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
QPlatformWindow subclasses can re-implement this function to
provide display refresh synchronized updates. The event
- should be delivered using QWindowPrivate::deliverUpdateRequest()
+ should be delivered using QPlatformWindow::deliverUpdateRequest()
to not get out of sync with the the internal state of QWindow.
The default implementation posts an UpdateRequest event to the
@@ -729,12 +743,28 @@ void QPlatformWindow::requestUpdate()
}
QWindow *w = window();
- QWindowPrivate *wp = (QWindowPrivate *) QObjectPrivate::get(w);
+ QWindowPrivate *wp = qt_window_private(w);
Q_ASSERT(wp->updateTimer == 0);
wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer);
}
/*!
+ Delivers an QEvent::UpdateRequest event to the window.
+
+ QPlatformWindow subclasses can re-implement this function to
+ provide e.g. logging or tracing of the delivery, but should
+ always call the base class function.
+*/
+void QPlatformWindow::deliverUpdateRequest()
+{
+ QWindow *w = window();
+ QWindowPrivate *wp = qt_window_private(w);
+ wp->updateRequestPending = false;
+ QEvent request(QEvent::UpdateRequest);
+ QCoreApplication::sendEvent(w, &request);
+}
+
+/*!
Returns the QWindow minimum size.
*/
QSize QPlatformWindow::windowMinimumSize() const
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index 84dff681d5..2fe8ad94e6 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -100,6 +100,7 @@ public:
virtual void setWindowTitle(const QString &title);
virtual void setWindowFilePath(const QString &title);
virtual void setWindowIcon(const QIcon &icon);
+ virtual bool close();
virtual void raise();
virtual void lower();
@@ -143,6 +144,7 @@ public:
const QRect &initialGeometry, int defaultWidth, int defaultHeight);
virtual void requestUpdate();
+ virtual void deliverUpdateRequest();
// Window property accessors. Platform plugins should use these
// instead of accessing QWindow directly.
diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp
index 6c19eab287..8e09c97806 100644
--- a/src/gui/kernel/qshortcutmap.cpp
+++ b/src/gui/kernel/qshortcutmap.cpp
@@ -540,6 +540,19 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl,
{
Q_D(QShortcutMap);
QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
+#if defined(DEBUG_QSHORTCUTMAP)
+ {
+ QDebug debug = qDebug().nospace();
+ debug << __FUNCTION__ << '(' << e << ", ignoredModifiers="
+ << Qt::KeyboardModifiers(ignoredModifiers) << "), possibleKeys=(";
+ for (int i = 0, size = possibleKeys.size(); i < size; ++i) {
+ if (i)
+ debug << ", ";
+ debug << QKeySequence(possibleKeys.at(i));
+ }
+ debug << ')';
+ }
+#endif // DEBUG_QSHORTCUTMAP
int pkTotal = possibleKeys.count();
if (!pkTotal)
return;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 2c7e061bcf..2eee8928e4 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -113,9 +113,10 @@ QT_BEGIN_NAMESPACE
physical area of the screen. On windowing systems that have exposure
notifications, the isExposed() accessor describes whether the window should
be treated as directly visible on screen. The exposeEvent() function is
- called whenever the windows exposure in the windowing system changes. On
- windowing systems that do not make this information visible to the
- application, isExposed() will simply return the same value as isVisible().
+ called whenever an area of the window is invalidated, for example due to the
+ exposure in the windowing system changing. On windowing systems that do not
+ make this information visible to the application, isExposed() will simply
+ return the same value as isVisible().
QWindow::Visibility queried through visibility() is a convenience API
combining the functions of visible() and windowStates().
@@ -2144,15 +2145,13 @@ bool QWindow::close()
if (!d->platformWindow)
return true;
- bool accepted = false;
- QWindowSystemInterface::handleCloseEvent(this, &accepted);
- QWindowSystemInterface::flushWindowSystemEvents();
- return accepted;
+ return d->platformWindow->close();
}
/*!
- The expose event (\a ev) is sent by the window system whenever the window's
- exposure on screen changes.
+ The expose event (\a ev) is sent by the window system whenever an area of
+ the window is invalidated, for example due to the exposure in the windowing
+ system changing.
The application can start rendering into the window with QBackingStore
and QOpenGLContext as soon as it gets an exposeEvent() such that
@@ -2334,7 +2333,8 @@ bool QWindow::event(QEvent *ev)
if (static_cast<QTimerEvent *>(ev)->timerId() == d->updateTimer) {
killTimer(d->updateTimer);
d->updateTimer = 0;
- d->deliverUpdateRequest();
+ if (d->platformWindow)
+ d->platformWindow->deliverUpdateRequest();
} else {
QObject::event(ev);
}
@@ -2360,10 +2360,8 @@ bool QWindow::event(QEvent *ev)
void QWindowPrivate::deliverUpdateRequest()
{
- Q_Q(QWindow);
- updateRequestPending = false;
- QEvent request(QEvent::UpdateRequest);
- QCoreApplication::sendEvent(q, &request);
+ if (platformWindow)
+ platformWindow->deliverUpdateRequest();
}
/*!
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 5243ae66a2..1b964ba913 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -335,12 +335,12 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QReg
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleCloseEvent(QWindow *window, bool *accepted)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleCloseEvent, QWindow *window, bool *accepted)
{
if (window) {
QWindowSystemInterfacePrivate::CloseEvent *e =
new QWindowSystemInterfacePrivate::CloseEvent(window, accepted);
- QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
+ QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
}
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index b22495f9d0..d584374fca 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -193,6 +193,7 @@ public:
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleExposeEvent(QWindow *window, const QRegion &region);
+ template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleCloseEvent(QWindow *window, bool *accepted = nullptr);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index b4657fa118..3a2393ea58 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -239,7 +239,7 @@ typedef unsigned long long int uint64_t;
typedef long int int32_t;
typedef long long int int64_t;
typedef unsigned long long int uint64_t;
-#elif defined(_WIN32) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600))
+#elif defined(_WIN32) && (defined(__GNUC__) || defined(_MSC_VER))
#include <stdint.h>
#elif defined(_WIN32)
typedef __int32 int32_t;
diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp
index 2f7afa4a66..f66193cb01 100644
--- a/src/gui/opengl/qopenglengineshadermanager.cpp
+++ b/src/gui/opengl/qopenglengineshadermanager.cpp
@@ -153,12 +153,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core;
code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core;
- code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO_core;
- code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM_core;
code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core;
code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core;
- code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO_core;
- code[MainFragmentShader_C] = qopenglslMainFragmentShader_C_core;
code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core;
code[MainFragmentShader] = qopenglslMainFragmentShader_core;
code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core;
@@ -203,12 +199,8 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader;
code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader;
- code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO;
- code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM;
code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO;
code[MainFragmentShader_M] = qopenglslMainFragmentShader_M;
- code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO;
- code[MainFragmentShader_C] = qopenglslMainFragmentShader_C;
code[MainFragmentShader_O] = qopenglslMainFragmentShader_O;
code[MainFragmentShader] = qopenglslMainFragmentShader;
code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays;
@@ -238,21 +230,20 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[RgbMaskWithGammaFragmentShader] = ""; //###
}
- // These shaders are not implemented yet and therefore are the same
- // for all profiles. Implementations should make a version for both
- // profiles and put the appropriate lines in the if-statement above.
+ // The composition shaders are just layout qualifiers and the same
+ // for all profiles that support them.
code[NoCompositionModeFragmentShader] = "";
- code[MultiplyCompositionModeFragmentShader] = ""; //###
- code[ScreenCompositionModeFragmentShader] = ""; //###
- code[OverlayCompositionModeFragmentShader] = ""; //###
- code[DarkenCompositionModeFragmentShader] = ""; //###
- code[LightenCompositionModeFragmentShader] = ""; //###
- code[ColorDodgeCompositionModeFragmentShader] = ""; //###
- code[ColorBurnCompositionModeFragmentShader] = ""; //###
- code[HardLightCompositionModeFragmentShader] = ""; //###
- code[SoftLightCompositionModeFragmentShader] = ""; //###
- code[DifferenceCompositionModeFragmentShader] = ""; //###
- code[ExclusionCompositionModeFragmentShader] = ""; //###
+ code[MultiplyCompositionModeFragmentShader] = qopenglslMultiplyCompositionModeFragmentShader;
+ code[ScreenCompositionModeFragmentShader] = qopenglslScreenCompositionModeFragmentShader;
+ code[OverlayCompositionModeFragmentShader] = qopenglslOverlayCompositionModeFragmentShader;
+ code[DarkenCompositionModeFragmentShader] = qopenglslDarkenCompositionModeFragmentShader;
+ code[LightenCompositionModeFragmentShader] = qopenglslLightenCompositionModeFragmentShader;
+ code[ColorDodgeCompositionModeFragmentShader] = qopenglslColorDodgeCompositionModeFragmentShader;
+ code[ColorBurnCompositionModeFragmentShader] = qopenglslColorBurnCompositionModeFragmentShader;
+ code[HardLightCompositionModeFragmentShader] = qopenglslHardLightCompositionModeFragmentShader;
+ code[SoftLightCompositionModeFragmentShader] = qopenglslSoftLightCompositionModeFragmentShader;
+ code[DifferenceCompositionModeFragmentShader] = qopenglslDifferenceCompositionModeFragmentShader;
+ code[ExclusionCompositionModeFragmentShader] = qopenglslExclusionCompositionModeFragmentShader;
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
@@ -612,8 +603,11 @@ void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mo
if (compositionMode == mode)
return;
+ bool wasAdvanced = compositionMode > QPainter::CompositionMode_Plus;
+ bool isAdvanced = mode > QPainter::CompositionMode_Plus;
+
compositionMode = mode;
- shaderProgNeedsChanging = true; //###
+ shaderProgNeedsChanging = shaderProgNeedsChanging || wasAdvanced || isAdvanced;
}
void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage)
@@ -783,21 +777,13 @@ bool QOpenGLEngineShaderManager::useCorrectShaderProg()
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays;
} else {
bool useGlobalOpacity = (opacityMode == UniformOpacity);
- if (hasCompose && hasMask && useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CMO;
- if (hasCompose && hasMask && !useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CM;
- if (!hasCompose && hasMask && useGlobalOpacity)
+ if (hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO;
- if (!hasCompose && hasMask && !useGlobalOpacity)
+ if (hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M;
- if (hasCompose && !hasMask && useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CO;
- if (hasCompose && !hasMask && !useGlobalOpacity)
- requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_C;
- if (!hasCompose && !hasMask && useGlobalOpacity)
+ if (!hasMask && useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O;
- if (!hasCompose && !hasMask && !useGlobalOpacity)
+ if (!hasMask && !useGlobalOpacity)
requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader;
}
diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h
index 377501457d..d43788d777 100644
--- a/src/gui/opengl/qopenglengineshadermanager_p.h
+++ b/src/gui/opengl/qopenglengineshadermanager_p.h
@@ -281,12 +281,8 @@ public:
AffinePositionWithTextureBrushVertexShader,
// MainFragmentShader_CMO must be first in the list:
- MainFragmentShader_CMO,
- MainFragmentShader_CM,
MainFragmentShader_MO,
MainFragmentShader_M,
- MainFragmentShader_CO,
- MainFragmentShader_C,
MainFragmentShader_O,
MainFragmentShader,
MainFragmentShader_ImageArrays,
diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h
index a165643839..5d9ee8110b 100644
--- a/src/gui/opengl/qopenglengineshadersource_p.h
+++ b/src/gui/opengl/qopenglengineshadersource_p.h
@@ -403,25 +403,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\
gl_FragColor = srcPixel() * opacity; \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CMO = "\n\
- uniform lowp float globalOpacity; \n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 applyMask(lowp vec4); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_CM = "\n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 applyMask(lowp vec4); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = applyMask(compose(srcPixel())); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_MO = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
@@ -439,23 +420,6 @@ static const char* const qopenglslMainFragmentShader_M = "\n\
gl_FragColor = applyMask(srcPixel()); \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CO = "\n\
- uniform lowp float globalOpacity; \n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = compose(srcPixel()*globalOpacity); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_C = "\n\
- lowp vec4 srcPixel(); \n\
- lowp vec4 compose(lowp vec4); \n\
- void main() \n\
- { \n\
- gl_FragColor = compose(srcPixel()); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_O = "\n\
uniform lowp float globalOpacity; \n\
lowp vec4 srcPixel(); \n\
@@ -513,22 +477,65 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\
return src * mask; \n\
}\n";
+static const char* const qopenglslMultiplyCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_multiply) out;\n\
+ #endif\n";
+
+static const char* const qopenglslScreenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_screen) out;\n\
+ #endif\n";
+
+static const char* const qopenglslOverlayCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_overlay) out;\n\
+ #endif\n";
+
+static const char* const qopenglslDarkenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_darken) out;\n\
+ #endif\n";
+
+static const char* const qopenglslLightenCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_lighten) out;\n\
+ #endif\n";
+
+static const char* const qopenglslColorDodgeCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_colordodge) out;\n\
+ #endif\n";
+
+static const char* const qopenglslColorBurnCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_colorburn) out;\n\
+ #endif\n";
+
+static const char* const qopenglslHardLightCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_hardlight) out;\n\
+ #endif\n";
+
+static const char* const qopenglslSoftLightCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_softlight) out;\n\
+ #endif\n";
+
+static const char* const qopenglslDifferenceCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_difference) out;\n\
+ #endif\n";
+
+static const char* const qopenglslExclusionCompositionModeFragmentShader = "\n\
+ #ifdef GL_KHR_blend_equation_advanced\n\
+ layout(blend_support_exclusion) out;\n\
+ #endif\n";
+
/*
Left to implement:
RgbMaskFragmentShader,
RgbMaskWithGammaFragmentShader,
-
- MultiplyCompositionModeFragmentShader,
- ScreenCompositionModeFragmentShader,
- OverlayCompositionModeFragmentShader,
- DarkenCompositionModeFragmentShader,
- LightenCompositionModeFragmentShader,
- ColorDodgeCompositionModeFragmentShader,
- ColorBurnCompositionModeFragmentShader,
- HardLightCompositionModeFragmentShader,
- SoftLightCompositionModeFragmentShader,
- DifferenceCompositionModeFragmentShader,
- ExclusionCompositionModeFragmentShader,
*/
/*
@@ -880,29 +887,6 @@ static const char* const qopenglslMainFragmentShader_ImageArrays_core =
fragColor = srcPixel() * opacity; \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CMO_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- uniform float globalOpacity; \n\
- vec4 srcPixel(); \n\
- vec4 applyMask(vec4); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_CM_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- vec4 srcPixel(); \n\
- vec4 applyMask(vec4); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = applyMask(compose(srcPixel())); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_MO_core =
"#version 150 core\n\
out vec4 fragColor; \n\
@@ -924,27 +908,6 @@ static const char* const qopenglslMainFragmentShader_M_core =
fragColor = applyMask(srcPixel()); \n\
}\n";
-static const char* const qopenglslMainFragmentShader_CO_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- uniform float globalOpacity; \n\
- vec4 srcPixel(); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = compose(srcPixel()*globalOpacity); \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_C_core =
- "#version 150 core\n\
- out vec4 fragColor; \n\
- vec4 srcPixel(); \n\
- vec4 compose(vec4); \n\
- void main() \n\
- { \n\
- fragColor = compose(srcPixel()); \n\
- }\n";
-
static const char* const qopenglslMainFragmentShader_O_core =
"#version 150 core\n\
out vec4 fragColor; \n\
@@ -1010,18 +973,6 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\
Left to implement:
RgbMaskFragmentShader_core,
RgbMaskWithGammaFragmentShader_core,
-
- MultiplyCompositionModeFragmentShader_core,
- ScreenCompositionModeFragmentShader_core,
- OverlayCompositionModeFragmentShader_core,
- DarkenCompositionModeFragmentShader_core,
- LightenCompositionModeFragmentShader_core,
- ColorDodgeCompositionModeFragmentShader_core,
- ColorBurnCompositionModeFragmentShader_core,
- HardLightCompositionModeFragmentShader_core,
- SoftLightCompositionModeFragmentShader_core,
- DifferenceCompositionModeFragmentShader_core,
- ExclusionCompositionModeFragmentShader_core,
*/
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index ff044a91da..236c81ac93 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -294,9 +294,19 @@ QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context)
static int qt_gl_resolve_features()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QOpenGLExtensionMatcher extensions;
+ int features = 0;
+ if ((extensions.match("GL_KHR_blend_equation_advanced")
+ || extensions.match("GL_NV_blend_equation_advanced")) &&
+ (extensions.match("GL_KHR_blend_equation_advanced_coherent")
+ || extensions.match("GL_NV_blend_equation_advanced_coherent"))) {
+ // We need both the advanced equations and the coherency for us
+ // to be able to easily use the new blend equations
+ features |= QOpenGLFunctions::BlendEquationAdvanced;
+ }
if (ctx->isOpenGLES()) {
// OpenGL ES
- int features = QOpenGLFunctions::Multitexture |
+ features |= QOpenGLFunctions::Multitexture |
QOpenGLFunctions::Shaders |
QOpenGLFunctions::Buffers |
QOpenGLFunctions::Framebuffers |
@@ -308,7 +318,6 @@ static int qt_gl_resolve_features()
QOpenGLFunctions::CompressedTextures |
QOpenGLFunctions::Multisample |
QOpenGLFunctions::StencilSeparate;
- QOpenGLExtensionMatcher extensions;
if (extensions.match("GL_IMG_texture_npot"))
features |= QOpenGLFunctions::NPOTTextures;
if (extensions.match("GL_OES_texture_npot"))
@@ -320,14 +329,18 @@ static int qt_gl_resolve_features()
if (!(renderer && strstr(renderer, "Mesa")))
features |= QOpenGLFunctions::TextureRGFormats;
}
- if (ctx->format().majorVersion() >= 3)
+ if (ctx->format().majorVersion() >= 3) {
features |= QOpenGLFunctions::MultipleRenderTargets;
+ if (ctx->format().minorVersion() >= 2 && extensions.match("GL_KHR_blend_equation_advanced_coherent")) {
+ // GL_KHR_blend_equation_advanced is included in OpenGL ES/3.2
+ features |= QOpenGLFunctions::BlendEquationAdvanced;
+ }
+ }
return features;
} else {
// OpenGL
- int features = QOpenGLFunctions::TextureRGFormats;
+ features |= QOpenGLFunctions::TextureRGFormats;
QSurfaceFormat format = QOpenGLContext::currentContext()->format();
- QOpenGLExtensionMatcher extensions;
if (format.majorVersion() >= 3)
features |= QOpenGLFunctions::Framebuffers | QOpenGLFunctions::MultipleRenderTargets;
diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h
index 1a43f13d9b..00287b0665 100644
--- a/src/gui/opengl/qopenglfunctions.h
+++ b/src/gui/opengl/qopenglfunctions.h
@@ -277,7 +277,8 @@ public:
NPOTTextureRepeat = 0x2000,
FixedFunctionPipeline = 0x4000,
TextureRGFormats = 0x8000,
- MultipleRenderTargets = 0x10000
+ MultipleRenderTargets = 0x10000,
+ BlendEquationAdvanced = 0x20000,
};
Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature)
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index 17dc9df619..fb7e6fce97 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -87,8 +87,27 @@
#include <QDebug>
-QT_BEGIN_NAMESPACE
+#ifndef GL_KHR_blend_equation_advanced
+#define GL_KHR_blend_equation_advanced 1
+#define GL_MULTIPLY_KHR 0x9294
+#define GL_SCREEN_KHR 0x9295
+#define GL_OVERLAY_KHR 0x9296
+#define GL_DARKEN_KHR 0x9297
+#define GL_LIGHTEN_KHR 0x9298
+#define GL_COLORDODGE_KHR 0x9299
+#define GL_COLORBURN_KHR 0x929A
+#define GL_HARDLIGHT_KHR 0x929B
+#define GL_SOFTLIGHT_KHR 0x929C
+#define GL_DIFFERENCE_KHR 0x929E
+#define GL_EXCLUSION_KHR 0x92A0
+#endif /* GL_KHR_blend_equation_advanced */
+
+#ifndef GL_KHR_blend_equation_advanced_coherent
+#define GL_KHR_blend_equation_advanced_coherent 1
+#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285
+#endif /* GL_KHR_blend_equation_advanced_coherent */
+QT_BEGIN_NAMESPACE
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
@@ -498,6 +517,21 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode()
// NOTE: The entire paint engine works on pre-multiplied data - which is why some of these
// composition modes look odd.
// qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode;
+ if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::BlendEquationAdvanced)) {
+ if (q->state()->composition_mode <= QPainter::CompositionMode_Plus) {
+ funcs.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
+ funcs.glBlendEquation(GL_FUNC_ADD);
+ } else {
+ funcs.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
+ }
+ shaderManager->setCompositionMode(q->state()->composition_mode);
+ } else {
+ if (q->state()->composition_mode > QPainter::CompositionMode_Plus) {
+ qWarning("Unsupported composition mode");
+ compositionModeDirty = false;
+ return;
+ }
+ }
switch(q->state()->composition_mode) {
case QPainter::CompositionMode_SourceOver:
funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -538,6 +572,39 @@ void QOpenGL2PaintEngineExPrivate::updateCompositionMode()
case QPainter::CompositionMode_Plus:
funcs.glBlendFunc(GL_ONE, GL_ONE);
break;
+ case QPainter::CompositionMode_Multiply:
+ funcs.glBlendEquation(GL_MULTIPLY_KHR);
+ break;
+ case QPainter::CompositionMode_Screen:
+ funcs.glBlendEquation(GL_SCREEN_KHR);
+ break;
+ case QPainter::CompositionMode_Overlay:
+ funcs.glBlendEquation(GL_OVERLAY_KHR);
+ break;
+ case QPainter::CompositionMode_Darken:
+ funcs.glBlendEquation(GL_DARKEN_KHR);
+ break;
+ case QPainter::CompositionMode_Lighten:
+ funcs.glBlendEquation(GL_LIGHTEN_KHR);
+ break;
+ case QPainter::CompositionMode_ColorDodge:
+ funcs.glBlendEquation(GL_COLORDODGE_KHR);
+ break;
+ case QPainter::CompositionMode_ColorBurn:
+ funcs.glBlendEquation(GL_COLORBURN_KHR);
+ break;
+ case QPainter::CompositionMode_HardLight:
+ funcs.glBlendEquation(GL_HARDLIGHT_KHR);
+ break;
+ case QPainter::CompositionMode_SoftLight:
+ funcs.glBlendEquation(GL_SOFTLIGHT_KHR);
+ break;
+ case QPainter::CompositionMode_Difference:
+ funcs.glBlendEquation(GL_DIFFERENCE_KHR);
+ break;
+ case QPainter::CompositionMode_Exclusion:
+ funcs.glBlendEquation(GL_EXCLUSION_KHR);
+ break;
default:
qWarning("Unsupported composition mode");
break;
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 2ae9c6d327..6d7aecac6f 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -496,6 +496,13 @@ static const char redefineHighp[] =
"#endif\n";
#endif
+// Boiler-plate header to have the layout attributes available we need later
+static const char blendEquationAdvancedHeader[] =
+ "#ifdef GL_KHR_blend_equation_advanced\n"
+ "#extension GL_ARB_fragment_coord_conventions : enable\n"
+ "#extension GL_KHR_blend_equation_advanced : enable\n"
+ "#endif\n";
+
struct QVersionDirectivePosition
{
Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1)
@@ -636,6 +643,10 @@ bool QOpenGLShader::compileSourceCode(const char *source)
}
}
}
+ if (d->shaderType == Fragment) {
+ sourceChunks.append(blendEquationAdvancedHeader);
+ sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1));
+ }
// The precision qualifiers are useful on OpenGL/ES systems,
// but usually not present on desktop systems.
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index c55bcb12c9..1d7375d1df 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -304,11 +304,6 @@ static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData);
#undef rgb
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-inline bool operator<(const RGBData &data1, const RGBData &data2)
-{ return qstrcmp(data1.name, data2.name) < 0; }
-#endif
-
inline bool operator<(const char *name, const RGBData &data)
{ return qstrcmp(name, data.name) < 0; }
inline bool operator<(const RGBData &data, const char *name)
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index f08038e34b..9db182e1a9 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -73,9 +73,6 @@ enum {
half_point = 1 << 15
};
-// must be multiple of 4 for easier SIMD implementations
-static const int buffer_size = 2048;
-
template<QImage::Format> Q_DECL_CONSTEXPR uint redWidth();
template<QImage::Format> Q_DECL_CONSTEXPR uint redShift();
template<QImage::Format> Q_DECL_CONSTEXPR uint greenWidth();
@@ -94,6 +91,10 @@ template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>
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; }
@@ -103,6 +104,15 @@ template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>
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; }
@@ -112,6 +122,10 @@ template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplie
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; }
@@ -121,6 +135,15 @@ template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplie
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; }
@@ -130,6 +153,10 @@ template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied
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; }
@@ -139,6 +166,15 @@ template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied
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; }
@@ -148,6 +184,10 @@ template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplie
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; }
@@ -157,6 +197,15 @@ template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplie
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> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel();
template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB16>() { return QPixelLayout::BPP16; }
@@ -168,6 +217,9 @@ template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB44
template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB6666_Premultiplied>() { return QPixelLayout::BPP24; }
+template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBX8888>() { return QPixelLayout::BPP32; }
+template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888>() { return QPixelLayout::BPP32; }
+template<> Q_DECL_CONSTEXPR QPixelLayout::BPP bitsPerPixel<QImage::Format_RGBA8888_Premultiplied>() { return QPixelLayout::BPP32; }
template<QImage::Format Format>
@@ -450,16 +502,68 @@ static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uin
return buffer;
}
+template<QImage::Format Format>
+static const uint *QT_FASTCALL rbSwap(uint *buffer, const uint *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);
+
+ for (int i = 0; i < count; ++i) {
+ const uint c = src[i];
+ const uint r = (c >> rShift) & redBlueMask;
+ const uint b = (c >> bShift) & redBlueMask;
+ buffer[i] = (c & alphaGreenMask)
+ | (r << bShift)
+ | (b << rShift);
+ }
+ return buffer;
+}
+
+static const uint *QT_FASTCALL rbSwap_rgb32(uint *buffer, const uint *src, int count)
+{
+ for (int i = 0; i < count; ++i) {
+ const uint c = src[i];
+ const uint ag = c & 0xff00ff00;
+ const uint rb = c & 0x00ff00ff;
+ buffer[i] = ag | (rb << 16) | (rb >> 16);
+ }
+ return buffer;
+}
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+template<>
+const uint *QT_FASTCALL rbSwap<QImage::Format_RGBA8888>(uint *buffer, const uint *src, int count)
+{
+ return rbSwap_rgb32(buffer, src, count);
+}
+#endif
+
+static const uint *QT_FASTCALL rbSwap_rgb30(uint *buffer, const uint *src, int count)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qRgbSwapRgb30(src[i]);
+ return buffer;
+}
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
{
return QPixelLayout{
- uchar(redWidth<Format>()), uchar(redShift<Format>()),
- uchar(greenWidth<Format>()), uchar(greenShift<Format>()),
- uchar(blueWidth<Format>()), uchar(blueShift<Format>()),
- 0, 0,
- false, bitsPerPixel<Format>(),
+ false,
+ false,
+ bitsPerPixel<Format>(),
+ rbSwap<Format>,
convertToRGB32<Format>,
convertRGBFromARGB32PM<Format, false>,
convertRGBFromARGB32PM<Format, true>,
@@ -470,11 +574,10 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutARGBPM()
{
return QPixelLayout{
- uchar(redWidth<Format>()), uchar(redShift<Format>()),
- uchar(greenWidth<Format>()), uchar(greenShift<Format>()),
- uchar(blueWidth<Format>()), uchar(blueShift<Format>()),
- uchar(alphaWidth<Format>()), uchar(alphaShift<Format>()),
- true, bitsPerPixel<Format>(),
+ true,
+ true,
+ bitsPerPixel<Format>(),
+ rbSwap<Format>,
convertARGBPMToARGB32PM<Format>,
convertARGBPMFromARGB32PM<Format, false>,
convertARGBPMFromARGB32PM<Format, true>,
@@ -482,8 +585,6 @@ template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixe
};
}
-#endif
-
// To convert in place, let 'dest' and 'src' be the same.
static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count,
const QVector<QRgb> *clut, QDitherInfo *)
@@ -953,16 +1054,15 @@ inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint
// convertFromArgb32() 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] = {
- { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0, 0 }, // Format_Invalid
- { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono
- { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB
- { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8
+ { false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
+ { false, false, QPixelLayout::BPP1MSB, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono
+ { false, false, QPixelLayout::BPP1LSB, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB
+ { false, false, QPixelLayout::BPP8, nullptr, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8
// Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong,
// but everywhere this generic conversion would be wrong is currently overloaded.
- { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32
- { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32
- { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied
-#ifdef Q_COMPILER_CONSTEXPR
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32
+ { true, false, QPixelLayout::BPP32, rbSwap_rgb32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied
pixelLayoutRGB<QImage::Format_RGB16>(),
pixelLayoutARGBPM<QImage::Format_ARGB8565_Premultiplied>(),
pixelLayoutRGB<QImage::Format_RGB666>(),
@@ -972,77 +1072,15 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
pixelLayoutRGB<QImage::Format_RGB888>(),
pixelLayoutRGB<QImage::Format_RGB444>(),
pixelLayoutARGBPM<QImage::Format_ARGB4444_Premultiplied>(),
-#else
- { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16,
- convertToRGB32<QImage::Format_RGB16>,
- convertRGBFromARGB32PM<QImage::Format_RGB16, false>,
- convertRGBFromARGB32PM<QImage::Format_RGB16, true>,
- convertToRGB64<QImage::Format_RGB16>,
- },
- { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24,
- convertARGBPMToARGB32PM<QImage::Format_ARGB8565_Premultiplied>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied, false>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB8565_Premultiplied, true>,
- convertARGBPMToARGB64PM<QImage::Format_ARGB8565_Premultiplied>,
- },
- { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24,
- convertToRGB32<QImage::Format_RGB666>,
- convertRGBFromARGB32PM<QImage::Format_RGB666, false>,
- convertRGBFromARGB32PM<QImage::Format_RGB666, true>,
- convertToRGB64<QImage::Format_RGB666>,
- },
- { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24,
- convertARGBPMToARGB32PM<QImage::Format_ARGB6666_Premultiplied>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied, false>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB6666_Premultiplied, true>,
- convertARGBPMToARGB64PM<QImage::Format_ARGB6666_Premultiplied>,
- },
- { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16,
- convertToRGB32<QImage::Format_RGB555>,
- convertRGBFromARGB32PM<QImage::Format_RGB555, false>,
- convertRGBFromARGB32PM<QImage::Format_RGB555, true>,
- convertToRGB64<QImage::Format_RGB555>,
- },
- { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24,
- convertARGBPMToARGB32PM<QImage::Format_ARGB8555_Premultiplied>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied, false>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB8555_Premultiplied, true>,
- convertARGBPMToARGB64PM<QImage::Format_ARGB8555_Premultiplied>,
- },
- { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24,
- convertToRGB32<QImage::Format_RGB888>,
- convertRGBFromARGB32PM<QImage::Format_RGB888, false>,
- convertRGBFromARGB32PM<QImage::Format_RGB888, true>,
- convertToRGB64<QImage::Format_RGB888>,
- },
- { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16,
- convertToRGB32<QImage::Format_RGB444>,
- convertRGBFromARGB32PM<QImage::Format_RGB444, false>,
- convertRGBFromARGB32PM<QImage::Format_RGB444, true>,
- convertToRGB64<QImage::Format_RGB444>,
- },
- { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16,
- convertARGBPMToARGB32PM<QImage::Format_ARGB4444_Premultiplied>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied, false>,
- convertARGBPMFromARGB32PM<QImage::Format_ARGB4444_Premultiplied, true>,
- convertARGBPMToARGB64PM<QImage::Format_ARGB4444_Premultiplied>,
- },
-#endif
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888
- { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888
- { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM}, // Format_RGBA8888_Premultiplied
-#else
- { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888
- { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32)
- { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied
-#endif
- { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30
- { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied
- { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30
- { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied
- { 0, 0, 0, 0, 0, 0, 8, 0, true, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8
- { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8
+ { false, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888
+ { true, false, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32)
+ { true, true, QPixelLayout::BPP32, rbSwap<QImage::Format_RGBA8888>, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertRGB30FromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_BGR30
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied
+ { false, false, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30
+ { true, true, QPixelLayout::BPP32, rbSwap_rgb30, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied
+ { true, true, QPixelLayout::BPP8, nullptr, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8
+ { false, false, QPixelLayout::BPP8, nullptr, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8
};
const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = {
@@ -1131,7 +1169,7 @@ static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, in
static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
{
const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
- uint buffer32[buffer_size];
+ uint buffer32[BufferSize];
const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length);
return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, ptr, length, 0, 0));
}
@@ -1304,14 +1342,14 @@ static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y
static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
{
- uint buf[buffer_size];
+ uint buf[BufferSize];
const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
StorePixelsFunc store = qStorePixels[layout->bpp];
uchar *dest = rasterBuffer->scanLine(y);
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *ptr = 0;
- if (!layout->premultiplied && !layout->alphaWidth)
+ if (!layout->premultiplied && !layout->hasAlphaChannel)
ptr = layout->convertFromRGB32(buf, buffer, l, 0, 0);
else
ptr = layout->convertFromARGB32PM(buf, buffer, l, 0, 0);
@@ -1331,15 +1369,15 @@ static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int len
static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
{
- uint buf[buffer_size];
+ uint buf[BufferSize];
const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
StorePixelsFunc store = qStorePixels[layout->bpp];
uchar *dest = rasterBuffer->scanLine(y);
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *ptr = 0;
convertFromRgb64(buf, buffer, l);
- if (!layout->premultiplied && !layout->alphaWidth)
+ if (!layout->premultiplied && !layout->hasAlphaChannel)
ptr = layout->convertFromRGB32(buf, buf, l, 0, 0);
else
ptr = layout->convertFromARGB32PM(buf, buf, l, 0, 0);
@@ -1554,7 +1592,7 @@ static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Op
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
if (layout->bpp != QPixelLayout::BPP32) {
- uint buffer32[buffer_size];
+ uint buffer32[BufferSize];
const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length);
return layout->convertToARGB64PM(buffer, ptr, length, data->texture.colorTable, 0);
} else {
@@ -1673,7 +1711,7 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
FetchPixelFunc fetch = qFetchPixel[layout->bpp];
const QVector<QRgb> *clut = data->texture.colorTable;
- uint buffer32[buffer_size];
+ uint buffer32[BufferSize];
QRgba64 *b = buffer;
if (data->fast_matrix) {
// The increment pr x in the scanline
@@ -1687,9 +1725,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
int i = 0, j = 0;
while (i < length) {
- if (j == buffer_size) {
- layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0);
- b += buffer_size;
+ if (j == BufferSize) {
+ layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0);
+ b += BufferSize;
j = 0;
}
int px = fx >> 16;
@@ -1725,9 +1763,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Oper
int i = 0, j = 0;
while (i < length) {
- if (j == buffer_size) {
- layout->convertToARGB64PM(b, buffer32, buffer_size, clut, 0);
- b += buffer_size;
+ if (j == BufferSize) {
+ layout->convertToARGB64PM(b, buffer32, BufferSize, clut, 0);
+ b += BufferSize;
j = 0;
}
const qreal iw = fw == 0 ? 1 : 1 / fw;
@@ -1921,7 +1959,7 @@ inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int,
}
enum FastTransformTypes {
- SimpleUpscaleTransform,
+ SimpleScaleTransform,
UpscaleTransform,
DownscaleTransform,
RotateTransform,
@@ -1929,11 +1967,38 @@ enum FastTransformTypes {
NFastTransformTypes
};
+// Completes the partial interpolation stored in IntermediateBuffer.
+// by performing the x-axis interpolation and joining the RB and AG buffers.
+static void QT_FASTCALL intermediate_adder(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx)
+{
+#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))
+ return intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx);
+#endif
+
+ // Switch to intermediate buffer coordinates
+ fx -= offset * fixed_scale;
+
+ while (b < end) {
+ const int x = (fx >> 16);
+
+ const uint distx = (fx & 0x0000ffff) >> 8;
+ const uint idistx = 256 - distx;
+ const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00;
+ const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00;
+ *b = (rb >> 8) | ag;
+ b++;
+ fx += fdx;
+ }
+ fx += offset * fixed_scale;
+}
+
typedef void (QT_FASTCALL *BilinearFastTransformHelper)(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy);
template<TextureBlendType blendType>
-static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(uint *b, uint *end, const QTextureData &image,
- int &fx, int &fy, int fdx, int /*fdy*/)
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
{
int y1 = (fy >> 16);
int y2;
@@ -1950,16 +2015,12 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
const int offset = (fx + adjust) >> 16;
int x = offset;
- // The idea is first to do the interpolation between the row s1 and the row s2
- // into an intermediate buffer, then we interpolate between two pixel of this buffer.
-
- // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
- // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
- // +1 for the last pixel to interpolate with, and +1 for rounding errors.
- quint32 intermediate_buffer[2][buffer_size + 2];
- // count is the size used in the intermediate_buffer.
+ IntermediateBuffer intermediate;
+ // count is the size used in the intermediate.buffer.
int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
- Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+ // length is supposed to be <= BufferSize either because data->m11 < 1 or
+ // data->m11 < 2, and any larger buffers split
+ Q_ASSERT(count <= BufferSize + 2);
int f = 0;
int lim = count;
if (blendType == BlendTransformedBilinearTiled) {
@@ -1974,8 +2035,8 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
do {
- intermediate_buffer[0][f] = rb;
- intermediate_buffer[1][f] = ag;
+ intermediate.buffer_rb[f] = rb;
+ intermediate.buffer_ag[f] = ag;
f++;
x++;
} while (x < image.x1 && f < lim);
@@ -2008,10 +2069,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
// Add the values, and shift to only keep 8 significant bits per colors
__m128i rAG =_mm_add_epi16(topAG, bottomAG);
rAG = _mm_srli_epi16(rAG, 8);
- _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
+ _mm_storeu_si128((__m128i*)(&intermediate.buffer_ag[f]), rAG);
__m128i rRB =_mm_add_epi16(topRB, bottomRB);
rRB = _mm_srli_epi16(rRB, 8);
- _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
+ _mm_storeu_si128((__m128i*)(&intermediate.buffer_rb[f]), rRB);
}
#elif defined(__ARM_NEON__)
const int16x8_t disty_ = vdupq_n_s16(disty);
@@ -2038,10 +2099,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
// Add the values, and shift to only keep 8 significant bits per colors
int16x8_t rAG = vaddq_s16(topAG, bottomAG);
rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
- vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
+ vst1q_s16((int16_t*)(&intermediate.buffer_ag[f]), rAG);
int16x8_t rRB = vaddq_s16(topRB, bottomRB);
rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
- vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
+ vst1q_s16((int16_t*)(&intermediate.buffer_rb[f]), rRB);
}
#endif
}
@@ -2055,28 +2116,13 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
uint t = s1[x];
uint b = s2[x];
- intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
x++;
}
- // Now interpolate the values from the intermediate_buffer to get the final result.
- fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates
-
- while (b < end) {
- int x1 = (fx >> 16);
- int x2 = x1 + 1;
- Q_ASSERT(x1 >= 0);
- Q_ASSERT(x2 < count);
-
- int distx = (fx & 0x0000ffff) >> 8;
- int idistx = 256 - distx;
- int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
- int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
- *b = rb | ag;
- b++;
- fx += fdx;
- }
+ // Now interpolate the values from the intermediate.buffer to get the final result.
+ intermediate_adder(b, end, intermediate, offset, fx, fdx);
}
template<TextureBlendType blendType>
@@ -2552,14 +2598,14 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint
static BilinearFastTransformHelper bilinearFastTransformHelperARGB32PM[2][NFastTransformTypes] = {
{
- fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinear>,
+ fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinear>,
fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinear>,
fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinear>,
fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinear>,
fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinear>
},
{
- fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinearTiled>,
+ fetchTransformedBilinearARGB32PM_simple_scale_helper<BlendTransformedBilinearTiled>,
fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinearTiled>,
fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinearTiled>,
fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinearTiled>,
@@ -2594,7 +2640,13 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
if (fdy == 0) { // simple scale, no rotation or shear
if (qAbs(fdx) <= fixed_scale) {
// simple scale up on X
- bilinearFastTransformHelperARGB32PM[tiled][SimpleUpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ } else if (qAbs(fdx) <= 2 * fixed_scale) {
+ // simple scale down on X, less than 2x
+ const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2);
+ bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer, buffer + mid, data->texture, fx, fy, fdx, fdy);
+ if (mid != length)
+ bilinearFastTransformHelperARGB32PM[tiled][SimpleScaleTransform](buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy);
} else if (qAbs(data->m22) < qreal(1./8.)) {
// scale up more than 8x (on Y)
bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
@@ -2663,8 +2715,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
}
template<TextureBlendType blendType, QPixelLayout::BPP bpp>
-static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, uint *end, const QTextureData &image,
- int &fx, int &fy, int fdx, int /*fdy*/)
+static void QT_FASTCALL fetchTransformedBilinear_simple_scale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
{
const QPixelLayout *layout = &qPixelLayouts[image.format];
const QVector<QRgb> *clut = image.colorTable;
@@ -2688,16 +2740,14 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b,
const int offset = (fx + adjust) >> 16;
int x = offset;
- // The idea is first to do the interpolation between the row s1 and the row s2
- // into an intermediate buffer, then we interpolate between two pixel of this buffer.
- // +1 for the last pixel to interpolate with, and +1 for rounding errors.
- uint buf1[buffer_size + 2];
- uint buf2[buffer_size + 2];
+ IntermediateBuffer intermediate;
+ uint *buf1 = intermediate.buffer_rb;
+ uint *buf2 = intermediate.buffer_ag;
const uint *ptr1;
const uint *ptr2;
int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
- Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+ Q_ASSERT(count <= BufferSize + 2);
if (blendType == BlendTransformedBilinearTiled) {
x %= image.width;
@@ -2729,6 +2779,7 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b,
buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
}
}
+ // Generate the rest by repeatedly repeating the previous set of pixels
for (int i = image.width; i < count; ++i) {
buf1[i] = buf1[i - image.width];
buf2[i] = buf2[i - image.width];
@@ -2761,22 +2812,8 @@ static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b,
}
}
- // Now interpolate the values from the intermediate_buffer to get the final result.
- fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates
-
- while (b < end) {
- int x1 = (fx >> 16);
- int x2 = x1 + 1;
- Q_ASSERT(x1 >= 0);
- Q_ASSERT(x2 < count);
-
- int distx = (fx & 0x0000ffff) >> 8;
- int idistx = 256 - distx;
- int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
- int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
- *b++ = rb | ag;
- fx += fdx;
- }
+ // Now interpolate the values from the intermediate.buffer to get the final result.
+ intermediate_adder(b, end, intermediate, offset, fx, fdx);
}
@@ -2926,15 +2963,20 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
if (fdy == 0) { // simple scale, no rotation or shear
if (qAbs(fdx) <= fixed_scale) { // scale up on X
- fetchTransformedBilinear_simple_upscale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy);
+ fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy);
+ } else if (qAbs(fdx) <= 2 * fixed_scale) { // scale down on X less than 2x
+ const int mid = (length * 2 < BufferSize) ? length : ((length + 1) / 2);
+ fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer, buffer + mid, data->texture, fx, fy, fdx, fdy);
+ if (mid != length)
+ fetchTransformedBilinear_simple_scale_helper<blendType, bpp>(buffer + mid, buffer + length, data->texture, fx, fy, fdx, fdy);
} else {
const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>;
- uint buf1[buffer_size];
- uint buf2[buffer_size];
+ uint buf1[BufferSize];
+ uint buf2[BufferSize];
uint *b = buffer;
while (length) {
- int len = qMin(length, buffer_size / 2);
+ int len = qMin(length, BufferSize / 2);
fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, 0);
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
@@ -2965,11 +3007,11 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
} else { // rotation or shear
const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>;
- uint buf1[buffer_size];
- uint buf2[buffer_size];
+ uint buf1[BufferSize];
+ uint buf2[BufferSize];
uint *b = buffer;
while (length) {
- int len = qMin(length, buffer_size / 2);
+ int len = qMin(length, BufferSize / 2);
fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
@@ -3019,15 +3061,15 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
- uint buf1[buffer_size];
- uint buf2[buffer_size];
+ uint buf1[BufferSize];
+ uint buf2[BufferSize];
uint *b = buffer;
- int distxs[buffer_size / 2];
- int distys[buffer_size / 2];
+ int distxs[BufferSize / 2];
+ int distys[BufferSize / 2];
while (length) {
- int len = qMin(length, buffer_size / 2);
+ 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);
@@ -3104,13 +3146,13 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
if (fdy == 0) { //simple scale, no rotation
- uint sbuf1[buffer_size];
- uint sbuf2[buffer_size];
- quint64 buf1[buffer_size];
- quint64 buf2[buffer_size];
+ uint sbuf1[BufferSize];
+ uint sbuf2[BufferSize];
+ quint64 buf1[BufferSize];
+ quint64 buf2[BufferSize];
QRgba64 *b = buffer;
while (length) {
- int len = qMin(length, buffer_size / 2);
+ int len = qMin(length, BufferSize / 2);
int disty = (fy & 0x0000ffff);
#if defined(__SSE2__)
const __m128i vdy = _mm_set1_epi16(disty);
@@ -3148,15 +3190,15 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
b += len;
}
} else { //rotation
- uint sbuf1[buffer_size];
- uint sbuf2[buffer_size];
- quint64 buf1[buffer_size];
- quint64 buf2[buffer_size];
+ uint sbuf1[BufferSize];
+ uint sbuf2[BufferSize];
+ quint64 buf1[BufferSize];
+ quint64 buf2[BufferSize];
QRgba64 *end = buffer + length;
QRgba64 *b = buffer;
while (b < end) {
- int len = qMin(length, buffer_size / 2);
+ int len = qMin(length, BufferSize / 2);
fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
@@ -3187,17 +3229,17 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
FetchPixelFunc fetch = qFetchPixel[layout->bpp];
- uint sbuf1[buffer_size];
- uint sbuf2[buffer_size];
- quint64 buf1[buffer_size];
- quint64 buf2[buffer_size];
+ uint sbuf1[BufferSize];
+ uint sbuf2[BufferSize];
+ quint64 buf1[BufferSize];
+ quint64 buf2[BufferSize];
QRgba64 *b = buffer;
- int distxs[buffer_size / 2];
- int distys[buffer_size / 2];
+ int distxs[BufferSize / 2];
+ int distys[BufferSize / 2];
while (length) {
- int len = qMin(length, buffer_size / 2);
+ 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);
@@ -3302,6 +3344,15 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled
};
+static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
+ fetchUntransformed, // Untransformed
+ fetchUntransformed, // Tiled
+ fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed
+ fetchTransformed<BlendTransformedTiled, QPixelLayout::BPP16>, // TransformedTiled
+ fetchTransformedBilinear<BlendTransformedBilinear, QPixelLayout::BPP16>, // TransformedBilinear
+ fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled
+};
+
static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
@@ -3326,6 +3377,8 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage:
return sourceFetchARGB32PM[blendType];
if (blendType == BlendUntransformed || blendType == BlendTiled)
return sourceFetchUntransformed[format];
+ if (qPixelLayouts[format].bpp == QPixelLayout::BPP16)
+ return sourceFetchAny16[blendType];
if (qPixelLayouts[format].bpp == QPixelLayout::BPP32)
return sourceFetchAny32[blendType];
return sourceFetchGeneric[blendType];
@@ -3727,7 +3780,7 @@ static
void blend_color_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
Operator op = getOperator(data, spans, count);
const uint color = data->solid.color.toArgb32();
@@ -3735,7 +3788,7 @@ void blend_color_generic(int count, const QSpan *spans, void *userData)
int x = spans->x;
int length = spans->len;
while (length) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
op.funcSolid(dest, l, color, spans->coverage);
if (op.destStore)
@@ -3787,14 +3840,27 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
return blend_color_generic(count, spans, userData);
}
- quint64 buffer[buffer_size];
+ quint64 buffer[BufferSize];
const QRgba64 color = data->solid.color;
+ bool solidFill = data->rasterBuffer->compositionMode == QPainter::CompositionMode_Source
+ || (data->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver && color.isOpaque());
+ bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
while (count--) {
int x = spans->x;
int length = spans->len;
+ if (solidFill && isBpp32 && spans->coverage == 255) {
+ // If dest doesn't matter we don't need to bother with blending or converting all the identical pixels
+ if (length > 0) {
+ op.destStore64(data->rasterBuffer, x, spans->y, &color, 1);
+ uint *dest = (uint*)data->rasterBuffer->scanLine(spans->y) + x;
+ qt_memfill32(dest + 1, dest[0], length - 1);
+ length = 0;
+ }
+ }
+
while (length) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l);
op.funcSolid64(dest, l, color, spans->coverage);
op.destStore64(data->rasterBuffer, x, spans->y, dest, l);
@@ -3899,7 +3965,7 @@ void handleSpans(int count, const QSpan *spans, const QSpanData *data, T &handle
int length = right - x;
while (length) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
length -= l;
int process_length = l;
@@ -3946,8 +4012,8 @@ struct QBlendBase
BlendType *dest;
- BlendType buffer[buffer_size];
- BlendType src_buffer[buffer_size];
+ BlendType buffer[BufferSize];
+ BlendType src_buffer[BufferSize];
};
class BlendSrcGeneric : public QBlendBase<uint>
@@ -4031,8 +4097,8 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[buffer_size];
- uint src_buffer[buffer_size];
+ uint buffer[BufferSize];
+ uint src_buffer[BufferSize];
Operator op = getOperator(data, spans, count);
const int image_width = data->texture.width;
@@ -4056,7 +4122,7 @@ static void blend_untransformed_generic(int count, const QSpan *spans, void *use
if (length > 0) {
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
op.func(dest, src, l, coverage);
@@ -4081,8 +4147,8 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_untransformed_generic(count, spans, userData);
}
- quint64 buffer[buffer_size];
- quint64 src_buffer[buffer_size];
+ quint64 buffer[BufferSize];
+ quint64 src_buffer[BufferSize];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -4105,7 +4171,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
if (length > 0) {
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l);
QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l);
op.func64(dest, src, l, coverage);
@@ -4269,8 +4335,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- uint buffer[buffer_size];
- uint src_buffer[buffer_size];
+ uint buffer[BufferSize];
+ uint src_buffer[BufferSize];
Operator op = getOperator(data, spans, count);
const int image_width = data->texture.width;
@@ -4296,8 +4362,8 @@ static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
+ if (BufferSize < l)
+ l = BufferSize;
const uint *src = op.srcFetch(src_buffer, &op, data, sy, sx, l);
uint *dest = op.destFetch ? op.destFetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
op.func(dest, src, l, coverage);
@@ -4322,8 +4388,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_tiled_generic(count, spans, userData);
}
- quint64 buffer[buffer_size];
- quint64 src_buffer[buffer_size];
+ quint64 buffer[BufferSize];
+ quint64 src_buffer[BufferSize];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -4335,6 +4401,50 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
if (yoff < 0)
yoff += image_height;
+ bool isBpp32 = qPixelLayouts[data->rasterBuffer->format].bpp == QPixelLayout::BPP32;
+ if (op.destFetch64 == destFetch64Undefined && image_width <= BufferSize && isBpp32) {
+ // If destination isn't blended into the result, we can do the tiling directly on destination pixels.
+ while (count--) {
+ int x = spans->x;
+ int y = spans->y;
+ 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;
+
+ int sl = qMin(image_width, length);
+ if (sx > 0 && sl > 0) {
+ int l = qMin(image_width - sx, sl);
+ const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l);
+ op.destStore64(data->rasterBuffer, x, y, src, l);
+ x += l;
+ sx += l;
+ sl -= l;
+ if (sx >= image_width)
+ sx = 0;
+ }
+ if (sl > 0) {
+ Q_ASSERT(sx == 0);
+ const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, sl);
+ op.destStore64(data->rasterBuffer, x, y, src, sl);
+ x += sl;
+ sx += sl;
+ sl -= sl;
+ 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];
+ }
+ ++spans;
+ }
+ return;
+ }
+
while (count--) {
int x = spans->x;
int length = spans->len;
@@ -4348,8 +4458,8 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
+ if (BufferSize < l)
+ l = BufferSize;
const QRgba64 *src = op.srcFetch64((QRgba64 *)src_buffer, &op, data, sy, sx, l);
QRgba64 *dest = op.destFetch64((QRgba64 *)buffer, data->rasterBuffer, x, spans->y, l);
op.func64(dest, src, l, coverage);
@@ -4398,8 +4508,8 @@ static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
+ 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);
@@ -4458,8 +4568,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
int tx = x;
while (length) {
int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
+ 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));
@@ -4494,8 +4604,8 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
if (alpha > 0) {
while (length) {
int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
+ if (BufferSize < l)
+ l = BufferSize;
quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
const quint16 *src = (const quint16 *)data->texture.scanLine(sy) + sx;
blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
@@ -4511,199 +4621,6 @@ static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
}
}
-static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData*>(userData);
- QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
-
- if (data->texture.format != QImage::Format_RGB16
- || (mode != QPainter::CompositionMode_SourceOver
- && mode != QPainter::CompositionMode_Source))
- {
- blend_src_generic(count, spans, userData);
- return;
- }
-
- quint16 buffer[buffer_size];
-
- const int src_minx = data->texture.x1;
- const int src_miny = data->texture.y1;
- const int src_maxx = data->texture.x2 - 1;
- const int src_maxy = data->texture.y2 - 1;
-
- if (data->fast_matrix) {
- // The increment pr x in the scanline
- const int fdx = (int)(data->m11 * fixed_scale);
- const int fdy = (int)(data->m12 * fixed_scale);
-
- while (count--) {
- const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- const quint8 alpha = (coverage + 1) >> 3;
- const quint8 ialpha = 0x20 - alpha;
- if (alpha == 0) {
- ++spans;
- continue;
- }
-
- quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
- const qreal cx = spans->x + qreal(0.5);
- const qreal cy = spans->y + qreal(0.5);
- int x = int((data->m21 * cy
- + data->m11 * cx + data->dx) * fixed_scale) - half_point;
- int y = int((data->m22 * cy
- + data->m12 * cx + data->dy) * fixed_scale) - half_point;
- int length = spans->len;
-
- while (length) {
- int l;
- quint16 *b;
- if (ialpha == 0) {
- l = length;
- b = dest;
- } else {
- l = qMin(length, buffer_size);
- b = buffer;
- }
- const quint16 *end = b + l;
-
- while (b < end) {
- int x1 = (x >> 16);
- int x2;
- int y1 = (y >> 16);
- int y2;
-
- fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
- fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
-
- const quint16 *src1 = (const quint16*)data->texture.scanLine(y1);
- const quint16 *src2 = (const quint16*)data->texture.scanLine(y2);
- quint16 tl = src1[x1];
- const quint16 tr = src1[x2];
- quint16 bl = src2[x1];
- const quint16 br = src2[x2];
-
- const uint distxsl8 = x & 0xff00;
- const uint distysl8 = y & 0xff00;
- const uint distx = distxsl8 >> 8;
- const uint disty = distysl8 >> 8;
- const uint distxy = distx * disty;
-
- const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
- const uint trw = distxsl8 - distxy; // distx * (256 - disty)
- const uint blw = distysl8 - distxy; // (256 - distx) * disty
- const uint brw = distxy; // distx * disty
- uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
- + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
- uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
- + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
- uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
- + (bl & 0x001f) * blw + (br & 0x001f) * brw);
- *b = quint16((red | green | blue) >> 16);
-
- ++b;
- x += fdx;
- y += fdy;
- }
-
- if (ialpha != 0)
- blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
-
- dest += l;
- length -= l;
- }
- ++spans;
- }
- } else {
- const qreal fdx = data->m11;
- const qreal fdy = data->m12;
- const qreal fdw = data->m13;
-
- while (count--) {
- const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- const quint8 alpha = (coverage + 1) >> 3;
- const quint8 ialpha = 0x20 - alpha;
- if (alpha == 0) {
- ++spans;
- continue;
- }
-
- quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
-
- const qreal cx = spans->x + qreal(0.5);
- const qreal cy = spans->y + qreal(0.5);
-
- qreal x = data->m21 * cy + data->m11 * cx + data->dx;
- qreal y = data->m22 * cy + data->m12 * cx + data->dy;
- qreal w = data->m23 * cy + data->m13 * cx + data->m33;
-
- int length = spans->len;
- while (length) {
- int l;
- quint16 *b;
- if (ialpha == 0) {
- l = length;
- b = dest;
- } else {
- l = qMin(length, buffer_size);
- b = buffer;
- }
- const quint16 *end = b + l;
-
- while (b < end) {
- const qreal iw = w == 0 ? 1 : 1 / w;
- const qreal px = x * iw - qreal(0.5);
- const qreal py = y * iw - qreal(0.5);
-
- int x1 = int(px) - (px < 0);
- int x2;
- int y1 = int(py) - (py < 0);
- int y2;
-
- fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
- fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
-
- const quint16 *src1 = (const quint16 *)data->texture.scanLine(y1);
- const quint16 *src2 = (const quint16 *)data->texture.scanLine(y2);
- quint16 tl = src1[x1];
- const quint16 tr = src1[x2];
- quint16 bl = src2[x1];
- const quint16 br = src2[x2];
-
- const uint distx = uint((px - x1) * 256);
- const uint disty = uint((py - y1) * 256);
- const uint distxsl8 = distx << 8;
- const uint distysl8 = disty << 8;
- const uint distxy = distx * disty;
-
- const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
- const uint trw = distxsl8 - distxy; // distx * (256 - disty)
- const uint blw = distysl8 - distxy; // (256 - distx) * disty
- const uint brw = distxy; // distx * disty
- uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
- + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
- uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
- + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
- uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
- + (bl & 0x001f) * blw + (br & 0x001f) * brw);
- *b = quint16((red | green | blue) >> 16);
-
- ++b;
- x += fdx;
- y += fdy;
- w += fdw;
- }
-
- if (ialpha != 0)
- blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
-
- dest += l;
- length -= l;
- }
- ++spans;
- }
- }
-}
-
static void blend_transformed_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -4714,7 +4631,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
}
CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
quint32 mask = (data->texture.format == QImage::Format_RGB32) ? 0xff000000 : 0;
const int image_x1 = data->texture.x1;
@@ -4743,7 +4660,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
int length = spans->len;
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *end = buffer + l;
uint *b = buffer;
while (b < end) {
@@ -4780,7 +4697,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
int length = spans->len;
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *end = buffer + l;
uint *b = buffer;
while (b < end) {
@@ -4819,7 +4736,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa
return;
}
- quint16 buffer[buffer_size];
+ quint16 buffer[BufferSize];
const int image_x1 = data->texture.x1;
const int image_y1 = data->texture.y1;
const int image_x2 = data->texture.x2 - 1;
@@ -4855,7 +4772,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa
l = length;
b = dest;
} else {
- l = qMin(length, buffer_size);
+ l = qMin(length, BufferSize);
b = buffer;
}
const quint16 *end = b + l;
@@ -4910,7 +4827,7 @@ static void blend_transformed_rgb565(int count, const QSpan *spans, void *userDa
l = length;
b = dest;
} else {
- l = qMin(length, buffer_size);
+ l = qMin(length, BufferSize);
b = buffer;
}
const quint16 *end = b + l;
@@ -4952,7 +4869,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us
}
CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
- uint buffer[buffer_size];
+ uint buffer[BufferSize];
int image_width = data->texture.width;
int image_height = data->texture.height;
@@ -4980,7 +4897,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
int length = spans->len;
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *end = buffer + l;
uint *b = buffer;
int px16 = x % (image_width << 16);
@@ -5034,7 +4951,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
int length = spans->len;
while (length) {
- int l = qMin(length, buffer_size);
+ int l = qMin(length, BufferSize);
const uint *end = buffer + l;
uint *b = buffer;
while (b < end) {
@@ -5085,7 +5002,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *
return;
}
- quint16 buffer[buffer_size];
+ quint16 buffer[BufferSize];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -5119,7 +5036,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *
l = length;
b = dest;
} else {
- l = qMin(length, buffer_size);
+ l = qMin(length, BufferSize);
b = buffer;
}
const quint16 *end = b + l;
@@ -5179,7 +5096,7 @@ static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *
l = length;
b = dest;
} else {
- l = qMin(length, buffer_size);
+ l = qMin(length, BufferSize);
b = buffer;
}
const quint16 *end = b + l;
@@ -5237,7 +5154,7 @@ static const ProcessSpans processTextureSpansRGB16[NBlendTypes] = {
blend_tiled_rgb565, // Tiled
blend_transformed_rgb565, // Transformed
blend_transformed_tiled_rgb565, // TransformedTiled
- blend_transformed_bilinear_rgb565, // TransformedBilinear
+ blend_src_generic, // TransformedBilinear
blend_src_generic // TransformedBilinearTiled
};
@@ -5533,7 +5450,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
}
- quint64 buffer[buffer_size];
+ quint64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
@@ -5542,7 +5459,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
int i = x;
int length = mapWidth;
while (length > 0) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l);
for (int j=0; j < l; ++j) {
const int coverage = map[j + (i - x)];
@@ -5571,7 +5488,7 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
if (end <= start)
continue;
- Q_ASSERT(end - start <= buffer_size);
+ Q_ASSERT(end - start <= BufferSize);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start);
for (int xp=start; xp<end; ++xp) {
@@ -5810,7 +5727,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
}
- quint64 buffer[buffer_size];
+ quint64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
@@ -5819,7 +5736,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
int i = x;
int length = mapWidth;
while (length > 0) {
- int l = qMin(buffer_size, length);
+ int l = qMin(BufferSize, length);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l);
for (int j=0; j < l; ++j) {
const uint coverage = src[j + (i - x)];
@@ -5848,7 +5765,7 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
int end = qMin<int>(x + mapWidth, clip.x + clip.len);
if (end <= start)
continue;
- Q_ASSERT(end - start <= buffer_size);
+ Q_ASSERT(end - start <= BufferSize);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start);
for (int xp=start; xp<end; ++xp) {
@@ -5938,8 +5855,26 @@ static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
int x, int y, int width, int height,
const QRgba64 &color)
{
+ const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
+ quint32 c32 = color.toArgb32();
+ layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr);
+ quint16 c16;
+ storePixel<QPixelLayout::BPP16>(reinterpret_cast<uchar *>(&c16), 0, c32);
qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
- color.toRgb16(), x, y, width, height, rasterBuffer->bytesPerLine());
+ c16, x, y, width, height, rasterBuffer->bytesPerLine());
+}
+
+static void qt_rectfill_quint24(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ const QRgba64 &color)
+{
+ const QPixelLayout &layout = qPixelLayouts[rasterBuffer->format];
+ quint32 c32 = color.toArgb32();
+ layout.convertFromARGB32PM(&c32, &c32, 1, nullptr, nullptr);
+ quint24 c24;
+ storePixel<QPixelLayout::BPP24>(reinterpret_cast<uchar *>(&c24), 0, c32);
+ qt_rectfill<quint24>(reinterpret_cast<quint24 *>(rasterBuffer->buffer()),
+ c24, x, y, width, height, rasterBuffer->bytesPerLine());
}
static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer,
@@ -6059,7 +5994,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint24
},
// Format_RGB666
{
@@ -6068,7 +6003,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint24
},
// Format_ARGB6666_Premultiplied
{
@@ -6077,7 +6012,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint24
},
// Format_RGB555
{
@@ -6086,7 +6021,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint16
},
// Format_ARGB8555_Premultiplied
{
@@ -6095,7 +6030,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint24
},
// Format_RGB888
{
@@ -6104,7 +6039,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint24
},
// Format_RGB444
{
@@ -6113,7 +6048,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint16
},
// Format_ARGB4444_Premultiplied
{
@@ -6122,7 +6057,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
0,
qt_alphamapblit_generic,
qt_alphargbblit_generic,
- 0
+ qt_rectfill_quint16
},
// Format_RGBX8888
{
@@ -6411,14 +6346,14 @@ static void qInitDrawhelperFunctions()
qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2;
qt_functionForModeSolid64_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_rgb64_avx2;
- extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
- int &fx, int &fy, int fdx, int /*fdy*/);
+ extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/);
extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
int &fx, int &fy, int fdx, int /*fdy*/);
extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image,
int &fx, int &fy, int fdx, int fdy);
- bilinearFastTransformHelperARGB32PM[0][SimpleUpscaleTransform] = fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2;
+ bilinearFastTransformHelperARGB32PM[0][SimpleScaleTransform] = fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2;
bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2;
bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2;
}
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index 3a70524a9d..1c225b4568 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -45,8 +45,6 @@
QT_BEGIN_NAMESPACE
-static Q_CONSTEXPR int BufferSize = 2048;
-
enum {
FixedScale = 1 << 16,
HalfPoint = 1 << 15
@@ -576,8 +574,10 @@ inline void fetchTransformedBilinear_pixelBounds(int, int l1, int l2, int &v1, i
Q_ASSERT(v2 >= l1 && v2 <= l2);
}
-void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
- int &fx, int &fy, int fdx, int /*fdy*/)
+void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx);
+
+void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_scale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
{
int y1 = (fy >> 16);
int y2;
@@ -594,16 +594,12 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
const int offset = (fx + adjust) >> 16;
int x = offset;
- // The idea is first to do the interpolation between the row s1 and the row s2
- // into an intermediate buffer, then we interpolate between two pixel of this buffer.
-
- // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
- // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
- // +1 for the last pixel to interpolate with, and +1 for rounding errors.
- quint32 intermediate_buffer[2][BufferSize + 2];
+ IntermediateBuffer intermediate;
// count is the size used in the intermediate_buffer.
int count = (qint64(length) * qAbs(fdx) + FixedScale - 1) / FixedScale + 2;
- Q_ASSERT(count <= BufferSize + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+ // length is supposed to be <= BufferSize either because data->m11 < 1 or
+ // data->m11 < 2, and any larger buffers split
+ Q_ASSERT(count <= BufferSize + 2);
int f = 0;
int lim = qMin(count, image.x2 - x);
if (x < image.x1) {
@@ -613,8 +609,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
do {
- intermediate_buffer[0][f] = rb;
- intermediate_buffer[1][f] = ag;
+ intermediate.buffer_rb[f] = rb;
+ intermediate.buffer_ag[f] = ag;
f++;
x++;
} while (x < image.x1 && f < lim);
@@ -644,10 +640,10 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
// Add the values, and shift to only keep 8 significant bits per colors
__m256i rAG =_mm256_add_epi16(topAG, bottomAG);
rAG = _mm256_srli_epi16(rAG, 8);
- _mm256_storeu_si256((__m256i*)(&intermediate_buffer[1][f]), rAG);
+ _mm256_storeu_si256((__m256i*)(&intermediate.buffer_ag[f]), rAG);
__m256i rRB =_mm256_add_epi16(topRB, bottomRB);
rRB = _mm256_srli_epi16(rRB, 8);
- _mm256_storeu_si256((__m256i*)(&intermediate_buffer[0][f]), rRB);
+ _mm256_storeu_si256((__m256i*)(&intermediate.buffer_rb[f]), rRB);
}
for (; f < count; f++) { // Same as above but without simd
@@ -656,11 +652,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
uint t = s1[x];
uint b = s2[x];
- intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate.buffer_rb[f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate.buffer_ag[f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
x++;
}
+
// Now interpolate the values from the intermediate_buffer to get the final result.
+ intermediate_adder_avx2(b, end, intermediate, offset, fx, fdx);
+}
+
+void QT_FASTCALL intermediate_adder_avx2(uint *b, uint *end, const IntermediateBuffer &intermediate, int offset, int &fx, int fdx)
+{
fx -= offset * FixedScale;
const __m128i v_fdx = _mm_set1_epi32(fdx * 4);
@@ -669,8 +671,8 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
while (b < end - 3) {
const __m128i offset = _mm_srli_epi32(v_fx, 16);
- __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate_buffer[0], offset, 4);
- __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate_buffer[1], offset, 4);
+ __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate.buffer_rb, offset, 4);
+ __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate.buffer_ag, offset, 4);
__m128i vdx = _mm_and_si128(v_fx, _mm_set1_epi32(0x0000ffff));
vdx = _mm_srli_epi16(vdx, 8);
@@ -695,17 +697,17 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
v_fx = _mm_add_epi32(v_fx, v_fdx);
}
while (b < end) {
- int x = (fx >> 16);
-
- uint distx = (fx & 0x0000ffff) >> 8;
- uint idistx = 256 - distx;
+ const int x = (fx >> 16);
- uint rb = ((intermediate_buffer[0][x] * idistx + intermediate_buffer[0][x + 1] * distx) >> 8) & 0xff00ff;
- uint ag = (intermediate_buffer[1][x] * idistx + intermediate_buffer[1][x + 1] * distx) & 0xff00ff00;
- *b = rb | ag;
+ const uint distx = (fx & 0x0000ffff) >> 8;
+ const uint idistx = 256 - distx;
+ const uint rb = (intermediate.buffer_rb[x] * idistx + intermediate.buffer_rb[x + 1] * distx) & 0xff00ff00;
+ const uint ag = (intermediate.buffer_ag[x] * idistx + intermediate.buffer_ag[x + 1] * distx) & 0xff00ff00;
+ *b = (rb >> 8) | ag;
b++;
fx += fdx;
}
+ fx += offset * FixedScale;
}
void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index ebf215a3eb..4940026abb 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -784,6 +784,7 @@ static Q_ALWAYS_INLINE uint qAlphaRgb30(uint c)
}
struct quint24 {
+ quint24() = default;
quint24(uint value);
operator uint() const;
uchar data[3];
@@ -1191,6 +1192,22 @@ inline uint comp_func_Plus_one_pixel(uint d, const uint s)
#undef MIX
#undef AMIX
+// must be multiple of 4 for easier SIMD implementations
+static Q_CONSTEXPR int BufferSize = 2048;
+
+// A buffer of intermediate results used by simple bilinear scaling.
+struct IntermediateBuffer
+{
+ // The idea is first to do the interpolation between the row s1 and the row s2
+ // into this intermediate buffer, then later interpolate between two pixel of this buffer.
+ //
+ // buffer_rb is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
+ // buffer_ag is the alpha-green component of the pixel, in the form 0x00AA00GG
+ // +1 for the last pixel to interpolate with, and +1 for rounding errors.
+ quint32 buffer_rb[BufferSize+2];
+ quint32 buffer_ag[BufferSize+2];
+};
+
struct QDitherInfo {
int x;
int y;
@@ -1200,6 +1217,8 @@ typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, in
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
+typedef const uint *(QT_FASTCALL *RbSwapFunc)(uint *buffer, const uint *src, int count);
+
struct QPixelLayout
{
@@ -1215,17 +1234,10 @@ struct QPixelLayout
BPPCount
};
- // All numbers in bits.
- uchar redWidth;
- uchar redShift;
- uchar greenWidth;
- uchar greenShift;
- uchar blueWidth;
- uchar blueShift;
- uchar alphaWidth;
- uchar alphaShift;
+ bool hasAlphaChannel;
bool premultiplied;
BPP bpp;
+ RbSwapFunc rbSwap;
ConvertFunc convertToARGB32PM;
ConvertFunc convertFromARGB32PM;
ConvertFunc convertFromRGB32;
diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp
index 1c7d6471b6..613a686848 100644
--- a/src/gui/painting/qpagedpaintdevice.cpp
+++ b/src/gui/painting/qpagedpaintdevice.cpp
@@ -42,6 +42,41 @@
QT_BEGIN_NAMESPACE
+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()
{
}
@@ -61,9 +96,11 @@ QPagedPaintDevicePrivate::~QPagedPaintDevicePrivate()
/*!
Constructs a new paged paint device.
+
+ \deprecated
*/
QPagedPaintDevice::QPagedPaintDevice()
- : d(new QPagedPaintDevicePrivate)
+ : d(new QDummyPagedPaintDevicePrivate)
{
}
@@ -263,7 +300,7 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd()
*/
void QPagedPaintDevice::setPageSize(PageSize size)
{
- d->m_pageLayout.setPageSize(QPageSize(QPageSize::PageSizeId(size)));
+ d->setPageSize(QPageSize(QPageSize::PageSizeId(size)));
}
/*!
@@ -271,7 +308,7 @@ void QPagedPaintDevice::setPageSize(PageSize size)
*/
QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const
{
- return PageSize(d->m_pageLayout.pageSize().id());
+ return PageSize(d->pageLayout().pageSize().id());
}
/*!
@@ -282,7 +319,7 @@ QPagedPaintDevice::PageSize QPagedPaintDevice::pageSize() const
*/
void QPagedPaintDevice::setPageSizeMM(const QSizeF &size)
{
- d->m_pageLayout.setPageSize(QPageSize(size, QPageSize::Millimeter));
+ d->setPageSize(QPageSize(size, QPageSize::Millimeter));
}
/*!
@@ -290,7 +327,7 @@ void QPagedPaintDevice::setPageSizeMM(const QSizeF &size)
*/
QSizeF QPagedPaintDevice::pageSizeMM() const
{
- return d->m_pageLayout.pageSize().size(QPageSize::Millimeter);
+ return d->pageLayout().pageSize().size(QPageSize::Millimeter);
}
/*!
@@ -305,8 +342,7 @@ QSizeF QPagedPaintDevice::pageSizeMM() const
*/
void QPagedPaintDevice::setMargins(const Margins &margins)
{
- d->m_pageLayout.setUnits(QPageLayout::Millimeter);
- d->m_pageLayout.setMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom));
+ d->setPageMargins(QMarginsF(margins.left, margins.top, margins.right, margins.bottom), QPageLayout::Millimeter);
}
/*!
@@ -318,7 +354,7 @@ void QPagedPaintDevice::setMargins(const Margins &margins)
*/
QPagedPaintDevice::Margins QPagedPaintDevice::margins() const
{
- QMarginsF margins = d->m_pageLayout.margins(QPageLayout::Millimeter);
+ QMarginsF margins = d->pageLayout().margins(QPageLayout::Millimeter);
Margins result;
result.left = margins.left();
result.top = margins.top();
@@ -413,7 +449,7 @@ bool QPagedPaintDevice::setPageOrientation(QPageLayout::Orientation orientation)
bool QPagedPaintDevice::setPageMargins(const QMarginsF &margins)
{
- return d->setPageMargins(margins);
+ return setPageMargins(margins, pageLayout().units());
}
/*!
@@ -458,23 +494,30 @@ QPageLayout QPagedPaintDevice::pageLayout() const
/*!
\internal
+ \deprecated
+
Returns the internal device page layout.
*/
QPageLayout QPagedPaintDevice::devicePageLayout() const
{
- return d->m_pageLayout;
+ qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, just use QPagedPaintDevice::pageLayout()");
+ return d->pageLayout();
}
/*!
\internal
+ \deprecated
+
Returns the internal device page layout.
*/
QPageLayout &QPagedPaintDevice::devicePageLayout()
{
- return d->m_pageLayout;
+ qWarning("QPagedPaintDevice::devicePageLayout() is deprecated, you shouldn't be using this at all.");
+ static QPageLayout dummy;
+ return dummy;
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h
index 66dd6fa8cf..c8957edab8 100644
--- a/src/gui/painting/qpagedpaintdevice.h
+++ b/src/gui/painting/qpagedpaintdevice.h
@@ -55,7 +55,7 @@ class QPagedPaintDevicePrivate;
class Q_GUI_EXPORT QPagedPaintDevice : public QPaintDevice
{
public:
- QPagedPaintDevice();
+ QT_DEPRECATED QPagedPaintDevice();
~QPagedPaintDevice();
virtual bool newPage() = 0;
@@ -243,8 +243,8 @@ public:
protected:
QPagedPaintDevice(QPagedPaintDevicePrivate *dd);
QPagedPaintDevicePrivate *dd();
- QPageLayout devicePageLayout() const;
- QPageLayout &devicePageLayout();
+ 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 a993ea4cac..3a43bd7828 100644
--- a/src/gui/painting/qpagedpaintdevice_p.h
+++ b/src/gui/painting/qpagedpaintdevice_p.h
@@ -60,8 +60,7 @@ class Q_GUI_EXPORT QPagedPaintDevicePrivate
{
public:
QPagedPaintDevicePrivate()
- : m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0)),
- fromPage(0),
+ : fromPage(0),
toPage(0),
pageOrderAscending(true),
printSelectionOnly(false)
@@ -70,46 +69,19 @@ public:
virtual ~QPagedPaintDevicePrivate();
- // ### Qt6 Remove these and make public class methods virtual
- virtual bool setPageLayout(const QPageLayout &newPageLayout)
- {
- m_pageLayout = newPageLayout;
- return m_pageLayout.isEquivalentTo(newPageLayout);;
- }
- virtual bool setPageSize(const QPageSize &pageSize)
- {
- m_pageLayout.setPageSize(pageSize);
- return m_pageLayout.pageSize().isEquivalentTo(pageSize);
- }
+ virtual bool setPageLayout(const QPageLayout &newPageLayout) = 0;
- virtual bool setPageOrientation(QPageLayout::Orientation orientation)
- {
- m_pageLayout.setOrientation(orientation);
- return m_pageLayout.orientation() == orientation;
- }
+ virtual bool setPageSize(const QPageSize &pageSize) = 0;
- virtual bool setPageMargins(const QMarginsF &margins)
- {
- return setPageMargins(margins, m_pageLayout.units());
- }
+ virtual bool setPageOrientation(QPageLayout::Orientation orientation) = 0;
- virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units)
- {
- m_pageLayout.setUnits(units);
- m_pageLayout.setMargins(margins);
- return m_pageLayout.margins() == margins && m_pageLayout.units() == units;
- }
+ virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) = 0;
- virtual QPageLayout pageLayout() const
- {
- return m_pageLayout;
- }
+ virtual QPageLayout pageLayout() const = 0;
static inline QPagedPaintDevicePrivate *get(QPagedPaintDevice *pd) { return pd->d; }
- QPageLayout m_pageLayout;
-
// These are currently required to keep QPrinter functionality working in QTextDocument::print()
int fromPage;
int toPage;
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index 2f24c7efcb..e6c5cabd7f 100644
--- a/src/gui/painting/qpdfwriter.cpp
+++ b/src/gui/painting/qpdfwriter.cpp
@@ -83,41 +83,28 @@ public:
{
// Try to set the paint engine page layout
pd->engine->setPageLayout(newPageLayout);
- // Set QPagedPaintDevice layout to match the current paint engine layout
- m_pageLayout = pd->engine->pageLayout();
- return m_pageLayout.isEquivalentTo(newPageLayout);
+ return pageLayout().isEquivalentTo(newPageLayout);
}
bool setPageSize(const QPageSize &pageSize) override
{
// Try to set the paint engine page size
pd->engine->setPageSize(pageSize);
- // Set QPagedPaintDevice layout to match the current paint engine layout
- m_pageLayout = pd->engine->pageLayout();
- return m_pageLayout.pageSize().isEquivalentTo(pageSize);
+ return pageLayout().pageSize().isEquivalentTo(pageSize);
}
bool setPageOrientation(QPageLayout::Orientation orientation) override
{
// Set the print engine value
pd->engine->setPageOrientation(orientation);
- // Set QPagedPaintDevice layout to match the current paint engine layout
- m_pageLayout = pd->engine->pageLayout();
- return m_pageLayout.orientation() == orientation;
- }
-
- bool setPageMargins(const QMarginsF &margins) override
- {
- return setPageMargins(margins, pageLayout().units());
+ return pageLayout().orientation() == orientation;
}
bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override
{
// Try to set engine margins
pd->engine->setPageMargins(margins, units);
- // Set QPagedPaintDevice layout to match the current paint engine layout
- m_pageLayout = pd->engine->pageLayout();
- return m_pageLayout.margins() == margins && m_pageLayout.units() == units;
+ return pageLayout().margins() == margins && pageLayout().units() == units;
}
QPageLayout pageLayout() const override
@@ -150,9 +137,6 @@ QPdfWriter::QPdfWriter(const QString &filename)
Q_D(QPdfWriter);
d->engine->setOutputFilename(filename);
-
- // Set QPagedPaintDevice layout to match the current paint engine layout
- devicePageLayout() = d->engine->pageLayout();
}
/*!
@@ -165,9 +149,6 @@ QPdfWriter::QPdfWriter(QIODevice *device)
Q_D(QPdfWriter);
d->engine->d_func()->outDevice = device;
-
- // Set QPagedPaintDevice layout to match the current paint engine layout
- devicePageLayout() = d->engine->pageLayout();
}
/*!
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 64adeaa260..70623939e1 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -345,13 +345,6 @@ static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = {
{ "none", StyleFeature_None }
};
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-static bool operator<(const QCssKnownValue &prop1, const QCssKnownValue &prop2)
-{
- return QString::compare(QString::fromLatin1(prop1.name), QLatin1String(prop2.name), Qt::CaseInsensitive) < 0;
-}
-#endif
-
static bool operator<(const QString &name, const QCssKnownValue &prop)
{
return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0;
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 44d1b2f201..129a326ba2 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -2908,7 +2908,11 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
html += QLatin1Char('>');
html += QLatin1String("<pre");
} else if (!list) {
- html += QLatin1String("<p");
+ int headingLevel = blockFormat.headingLevel();
+ if (headingLevel > 0 && headingLevel <= 6)
+ html += QLatin1String("<h") + QString::number(headingLevel);
+ else
+ html += QLatin1String("<p");
}
emitBlockAttributes(block);
@@ -2931,8 +2935,13 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
html += QLatin1String("</pre>");
else if (list)
html += QLatin1String("</li>");
- else
- html += QLatin1String("</p>");
+ else {
+ int headingLevel = blockFormat.headingLevel();
+ if (headingLevel > 0 && headingLevel <= 6)
+ html += QLatin1String("</h") + QString::number(headingLevel) + QLatin1Char('>');
+ else
+ html += QLatin1String("</p>");
+ }
if (list) {
if (list->itemNumber(block) == list->count() - 1) { // last item? close list
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index ea37695f4e..3ad49b3f88 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -420,7 +420,7 @@ static QTextListFormat::Style nextListStyle(QTextListFormat::Style style)
}
QTextHtmlImporter::QTextHtmlImporter(QTextDocument *_doc, const QString &_html, ImportMode mode, const QTextDocument *resourceProvider)
- : indent(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode)
+ : indent(0), headingLevel(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode)
{
cursor = QTextCursor(doc);
wsm = QTextHtmlParserNode::WhiteSpaceNormal;
@@ -747,8 +747,28 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processSpecialNodes()
return ContinueWithNextNode;
}
+ case Html_h1:
+ headingLevel = 1;
+ break;
+ case Html_h2:
+ headingLevel = 2;
+ break;
+ case Html_h3:
+ headingLevel = 3;
+ break;
+ case Html_h4:
+ headingLevel = 4;
+ break;
+ case Html_h5:
+ headingLevel = 5;
+ break;
+ case Html_h6:
+ headingLevel = 6;
+ break;
+
default: break;
}
+
return ContinueWithCurrentNode;
}
@@ -832,6 +852,15 @@ bool QTextHtmlImporter::closeTag()
}
}
break;
+ case Html_h1:
+ case Html_h2:
+ case Html_h3:
+ case Html_h4:
+ case Html_h5:
+ case Html_h6:
+ headingLevel = 0;
+ blockTagClosed = true;
+ break;
default:
if (closedNode->isBlock())
blockTagClosed = true;
@@ -1093,6 +1122,11 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
modifiedBlockFormat = true;
}
+ if (headingLevel) {
+ block.setHeadingLevel(headingLevel);
+ modifiedBlockFormat = true;
+ }
+
if (currentNode->blockFormat.propertyCount() > 0) {
modifiedBlockFormat = true;
block.merge(currentNode->blockFormat);
diff --git a/src/gui/text/qtextdocumentfragment_p.h b/src/gui/text/qtextdocumentfragment_p.h
index e8699545f7..02a6a429fa 100644
--- a/src/gui/text/qtextdocumentfragment_p.h
+++ b/src/gui/text/qtextdocumentfragment_p.h
@@ -152,6 +152,7 @@ private:
friend class QTypeInfo<List>;
QVector<List> lists;
int indent;
+ int headingLevel;
// insert a named anchor the next time we emit a char format,
// either in a block or in regular text
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index 9877a23fa6..d04dd08058 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -399,26 +399,6 @@ static bool operator<(const QCheckPoint &checkPoint, int pos)
return checkPoint.positionInFrame < pos;
}
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-//The STL implementation of MSVC 2008 requires the definitions
-
-static bool operator<(const QCheckPoint &checkPoint1, const QCheckPoint &checkPoint2)
-{
- return checkPoint1.y < checkPoint2.y;
-}
-
-static bool operator<(QFixed y, const QCheckPoint &checkPoint)
-{
- return y < checkPoint.y;
-}
-
-static bool operator<(int pos, const QCheckPoint &checkPoint)
-{
- return pos < checkPoint.positionInFrame;
-}
-
-#endif
-
static void fillBackground(QPainter *p, const QRectF &rect, QBrush brush, const QPointF &origin, const QRectF &gradientRect = QRectF())
{
p->save();
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 5e38311fa1..2d1f0fa823 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1927,7 +1927,7 @@ const QCharAttributes *QTextEngine::attributes() const
QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size());
for (int i = 0; i < layoutData->items.size(); ++i) {
- const QScriptItem &si = layoutData->items[i];
+ const QScriptItem &si = layoutData->items.at(i);
scriptItems[i].position = si.position;
scriptItems[i].script = si.analysis.script;
}
@@ -1944,14 +1944,14 @@ const QCharAttributes *QTextEngine::attributes() const
void QTextEngine::shape(int item) const
{
- if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) {
+ if (layoutData->items.at(item).analysis.flags == QScriptAnalysis::Object) {
ensureSpace(1);
if (block.docHandle()) {
docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)),
layoutData->items[item].position + block.position(),
format(&layoutData->items[item]));
}
- } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) {
+ } else if (layoutData->items.at(item).analysis.flags == QScriptAnalysis::Tab) {
// set up at least the ascent/descent/leading of the script item for the tab
fontEngine(layoutData->items[item],
&layoutData->items[item].ascent,
@@ -2064,7 +2064,7 @@ void QTextEngine::itemize() const
case QChar::Space:
case QChar::Nbsp:
if (option.flags() & QTextOption::ShowTabsAndSpaces) {
- analysis->flags = QScriptAnalysis::Space;
+ analysis->flags = (*uc == QChar::Space) ? QScriptAnalysis::Space : QScriptAnalysis::Nbsp;
analysis->bidiLevel = bidi.baseLevel;
break;
}
@@ -2193,9 +2193,9 @@ int QTextEngine::findItem(int strPos, int firstItem) const
int right = layoutData->items.size()-1;
while(left <= right) {
int middle = ((right-left)/2)+left;
- if (strPos > layoutData->items[middle].position)
+ if (strPos > layoutData->items.at(middle).position)
left = middle+1;
- else if(strPos < layoutData->items[middle].position)
+ else if (strPos < layoutData->items.at(middle).position)
right = middle-1;
else {
return middle;
@@ -2587,7 +2587,7 @@ void QTextEngine::justify(const QScriptLine &line)
int end = line.from + (int)line.length + line.trailingSpaces;
if (end == layoutData->string.length())
return; // no justification at end of paragraph
- if (end && layoutData->items[findItem(end-1)].analysis.flags == QScriptAnalysis::LineOrParagraphSeparator)
+ if (end && layoutData->items.at(findItem(end - 1)).analysis.flags == QScriptAnalysis::LineOrParagraphSeparator)
return; // no justification at the end of an explicitly separated line
}
@@ -2621,13 +2621,13 @@ void QTextEngine::justify(const QScriptLine &line)
// store pointers to the glyph data that could get reallocated by the shaping
// process.
for (int i = 0; i < nItems; ++i) {
- QScriptItem &si = layoutData->items[firstItem + i];
+ const QScriptItem &si = layoutData->items.at(firstItem + i);
if (!si.num_glyphs)
shape(firstItem + i);
}
for (int i = 0; i < nItems; ++i) {
- QScriptItem &si = layoutData->items[firstItem + i];
+ const QScriptItem &si = layoutData->items.at(firstItem + i);
int kashida_type = Justification_Arabic_Normal;
int kashida_pos = -1;
@@ -2923,7 +2923,7 @@ int QTextEngine::formatIndex(const QScriptItem *si) const
if (specialData && !specialData->resolvedFormats.isEmpty()) {
QTextFormatCollection *collection = formatCollection();
Q_ASSERT(collection);
- return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0]));
+ return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items.at(0)));
}
QTextDocumentPrivate *p = block.docHandle();
@@ -3129,7 +3129,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (!attributes)
return QString();
for (int i = 0; i < layoutData->items.size(); ++i) {
- QScriptItem &si = layoutData->items[i];
+ const QScriptItem &si = layoutData->items.at(i);
if (!si.num_glyphs)
shape(i);
@@ -3314,24 +3314,29 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
QList<QTextOption::Tab> tabArray = option.tabs();
if (!tabArray.isEmpty()) {
if (isRightToLeft()) { // rebase the tabArray positions.
- QList<QTextOption::Tab> newTabs;
- newTabs.reserve(tabArray.count());
- QList<QTextOption::Tab>::Iterator iter = tabArray.begin();
- while(iter != tabArray.end()) {
- QTextOption::Tab tab = *iter;
- if (tab.type == QTextOption::LeftTab)
- tab.type = QTextOption::RightTab;
- else if (tab.type == QTextOption::RightTab)
- tab.type = QTextOption::LeftTab;
- newTabs << tab;
- ++iter;
- }
- tabArray = newTabs;
- }
- for (int i = 0; i < tabArray.size(); ++i) {
- QFixed tab = QFixed::fromReal(tabArray[i].position) * dpiScale;
+ auto isLeftOrRightTab = [](const QTextOption::Tab &tab) {
+ return tab.type == QTextOption::LeftTab || tab.type == QTextOption::RightTab;
+ };
+ const auto cbegin = tabArray.cbegin();
+ const auto cend = tabArray.cend();
+ const auto cit = std::find_if(cbegin, cend, isLeftOrRightTab);
+ if (cit != cend) {
+ const int index = std::distance(cbegin, cit);
+ auto iter = tabArray.begin() + index;
+ const auto end = tabArray.end();
+ while (iter != end) {
+ QTextOption::Tab &tab = *iter;
+ if (tab.type == QTextOption::LeftTab)
+ tab.type = QTextOption::RightTab;
+ else if (tab.type == QTextOption::RightTab)
+ tab.type = QTextOption::LeftTab;
+ ++iter;
+ }
+ }
+ }
+ for (const QTextOption::Tab &tabSpec : qAsConst(tabArray)) {
+ QFixed tab = QFixed::fromReal(tabSpec.position) * dpiScale;
if (tab > x) { // this is the tab we need.
- QTextOption::Tab tabSpec = tabArray[i];
int tabSectionEnd = layoutData->string.count();
if (tabSpec.type == QTextOption::RightTab || tabSpec.type == QTextOption::CenterTab) {
// find next tab to calculate the width required.
@@ -3352,7 +3357,7 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
QFixed length;
// Calculate the length of text between this tab and the tabSectionEnd
for (int i=item; i < layoutData->items.count(); i++) {
- QScriptItem &item = layoutData->items[i];
+ const QScriptItem &item = layoutData->items.at(i);
if (item.position > tabSectionEnd || item.position <= si.position)
continue;
shape(i); // first, lets make sure relevant text is already shaped
@@ -3652,11 +3657,12 @@ int QTextEngine::lineNumberForTextPosition(int pos)
return -1;
}
-void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints)
+std::vector<int> QTextEngine::insertionPointsForLine(int lineNum)
{
QTextLineItemIterator iterator(this, lineNum);
- insertionPoints.reserve(iterator.line.length);
+ std::vector<int> insertionPoints;
+ insertionPoints.reserve(size_t(iterator.line.length));
bool lastLine = lineNum >= lines.size() - 1;
@@ -3674,25 +3680,22 @@ void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoi
insertionPoints.push_back(i);
}
}
+ return insertionPoints;
}
int QTextEngine::endOfLine(int lineNum)
{
- QVector<int> insertionPoints;
- insertionPointsForLine(lineNum, insertionPoints);
-
+ const auto insertionPoints = insertionPointsForLine(lineNum);
if (insertionPoints.size() > 0)
- return insertionPoints.constLast();
+ return insertionPoints.back();
return 0;
}
int QTextEngine::beginningOfLine(int lineNum)
{
- QVector<int> insertionPoints;
- insertionPointsForLine(lineNum, insertionPoints);
-
+ const auto insertionPoints = insertionPointsForLine(lineNum);
if (insertionPoints.size() > 0)
- return insertionPoints.constFirst();
+ return insertionPoints.front();
return 0;
}
@@ -3709,10 +3712,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation
if (lineNum < 0)
return pos;
- QVector<int> insertionPoints;
- insertionPointsForLine(lineNum, insertionPoints);
- int i, max = insertionPoints.size();
- for (i = 0; i < max; i++)
+ const auto insertionPoints = insertionPointsForLine(lineNum);
+ for (size_t i = 0, max = insertionPoints.size(); i < max; ++i)
if (pos == insertionPoints[i]) {
if (moveRight) {
if (i + 1 < max)
@@ -3990,7 +3991,7 @@ QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, co
QVarLengthArray<uchar> levels(nItems);
for (int i = 0; i < nItems; ++i)
- levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
+ levels[i] = eng->layoutData->items.at(i + firstItem).analysis.bidiLevel;
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
eng->shapeLine(line);
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index f9eb055478..e9187ea605 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -74,6 +74,7 @@
#include <private/qunicodetools_p.h>
#include <stdlib.h>
+#include <vector>
QT_BEGIN_NAMESPACE
@@ -142,9 +143,10 @@ struct Q_AUTOTEST_EXPORT QScriptAnalysis
LineOrParagraphSeparator = 4,
Space = 5,
SpaceTabOrObject = Space,
- Tab = 6,
+ Nbsp = 6,
+ Tab = 7,
TabOrObject = Tab,
- Object = 7
+ Object = 8
};
enum BidiFlags {
BidiBN = 1,
@@ -632,7 +634,7 @@ public:
int nextLogicalPosition(int oldPos) const;
int lineNumberForTextPosition(int pos);
int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
- void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints);
+ std::vector<int> insertionPointsForLine(int lineNum);
void resetFontEngineCache();
void enableDelayDecorations(bool enable = true) { delayDecorations = enable; }
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 08106db6ce..749a287941 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -514,7 +514,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value BlockFormat The object formats a text block
\value CharFormat The object formats a single character
\value ListFormat The object formats a list
- \omitvalue TableFormat Unused Value, a table's FormatType is FrameFormat.
+ \omitvalue TableFormat \omit Unused Value, a table's FormatType is FrameFormat. \endomit
\value FrameFormat The object formats a frame
\value UserFormat
@@ -556,6 +556,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value LineHeightType
\value BlockNonBreakableLines
\value BlockTrailingHorizontalRulerWidth The width of a horizontal ruler element.
+ \value HeadingLevel The level of a heading, for example 1 corresponds to an HTML H1 tag; otherwise 0.
+ This enum value has been added in Qt 5.12.
Character properties
@@ -2246,6 +2248,34 @@ QList<QTextOption::Tab> QTextBlockFormat::tabPositions() const
/*!
+ \fn void QTextBlockFormat::setHeadingLevel(int level)
+ \since 5.12
+
+ Sets the paragraph's heading level, where 1 is the highest-level heading
+ type (usually with the largest possible heading font size), and increasing
+ values are progressively deeper into the document (and usually with smaller
+ font sizes). For example when reading an HTML H1 tag, the heading level is
+ set to 1. Setting the heading level does not automatically change the font
+ size; however QTextDocumentFragment::fromHtml() sets both the heading level
+ and the font size simultaneously.
+
+ If the paragraph is not a heading, the level should be set to 0 (the default).
+
+ \sa headingLevel()
+*/
+
+
+/*!
+ \fn int QTextBlockFormat::headingLevel() const
+ \since 5.12
+
+ Returns the paragraph's heading level if it is a heading, or 0 if not.
+
+ \sa setHeadingLevel()
+*/
+
+
+/*!
\fn void QTextBlockFormat::setLineHeight(qreal height, int heightType)
\since 4.8
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index 28c3035537..8f8d3d4299 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -175,6 +175,7 @@ public:
LineHeightType = 0x1049,
BlockNonBreakableLines = 0x1050,
BlockTrailingHorizontalRulerWidth = 0x1060,
+ HeadingLevel = 0x1070,
// character properties
FirstFontProperty = 0x1FE0,
@@ -624,6 +625,11 @@ public:
inline int indent() const
{ return intProperty(BlockIndent); }
+ inline void setHeadingLevel(int alevel)
+ { setProperty(HeadingLevel, alevel); }
+ inline int headingLevel() const
+ { return intProperty(HeadingLevel); }
+
inline void setLineHeight(qreal height, int heightType)
{ setProperty(LineHeight, height); setProperty(LineHeightType, heightType); }
inline qreal lineHeight(qreal scriptLineHeight, qreal scaling) const;
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 9154182df1..4be800b251 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -448,13 +448,6 @@ static const QTextHtmlElement elements[Html_NumElements]= {
{ "var", Html_var, QTextHtmlElement::DisplayInline },
};
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-static bool operator<(const QTextHtmlElement &e1, const QTextHtmlElement &e2)
-{
- return QLatin1String(e1.name) < QLatin1String(e2.name);
-}
-#endif
-
static bool operator<(const QString &str, const QTextHtmlElement &e)
{
return str < QLatin1String(e.name);
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 6e824b2ed1..860d1e8c7c 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1006,10 +1006,8 @@ static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPo
}
if (lastSelectionWidth > 0) {
- QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
- rect.moveLeft(qFloor(rect.left()));
- rect.moveTop(qFloor(rect.top()));
- region->addRect(rect);
+ const QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
+ region->addRect(rect.toAlignedRect());
}
lastSelectionX = selectionX;
@@ -1017,10 +1015,8 @@ static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPo
}
}
if (lastSelectionWidth > 0) {
- QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
- rect.moveLeft(qFloor(rect.left()));
- rect.moveTop(qFloor(rect.top()));
- region->addRect(rect);
+ const QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
+ region->addRect(rect.toAlignedRect());
}
}
@@ -2135,7 +2131,7 @@ static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const Q
QBrush bg = chf.background();
if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
- p->fillRect(QRectF(qFloor(r.x()), qFloor(r.y()), r.width(), r.height()), bg);
+ p->fillRect(r.toAlignedRect(), bg);
if (c.style() != Qt::NoBrush) {
p->setPen(QPen(c, 0));
}
@@ -2614,12 +2610,13 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR
QPainterPrivate::get(p)->drawTextItem(pos, gf, eng);
}
- if (si.analysis.flags == QScriptAnalysis::Space
+ if ((si.analysis.flags == QScriptAnalysis::Space
+ || si.analysis.flags == QScriptAnalysis::Nbsp)
&& (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
QBrush c = format.foreground();
if (c.style() != Qt::NoBrush)
p->setPen(c.color());
- QChar visualSpace((ushort)0xb7);
+ QChar visualSpace(si.analysis.flags == QScriptAnalysis::Space ? (ushort)0xb7 : (ushort)0xb0);
p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
p->setPen(pen);
}
@@ -2845,9 +2842,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
bool rtl = eng->isRightToLeft();
eng->shapeLine(line);
- QVector<int> insertionPoints;
- if (visual && rtl)
- eng->insertionPointsForLine(lineNum, insertionPoints);
+ const auto insertionPoints = (visual && rtl) ? eng->insertionPointsForLine(lineNum) : std::vector<int>();
int nchars = 0;
for (int i = 0; i < nItems; ++i) {
int item = visualOrder[i]+firstItem;
@@ -2979,7 +2974,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
continue;
}
if (rtl && nchars > 0)
- return insertionPoints[lastLine ? nchars : nchars - 1];
+ return insertionPoints[size_t(lastLine ? nchars : nchars - 1)];
}
return eng->positionInLigature(&si, end, x, pos, -1,
cpos == QTextLine::CursorOnCharacter);
diff --git a/src/gui/text/qtextoption.cpp b/src/gui/text/qtextoption.cpp
index a3fa0e7351..2c2c05567f 100644
--- a/src/gui/text/qtextoption.cpp
+++ b/src/gui/text/qtextoption.cpp
@@ -307,7 +307,8 @@ QList<QTextOption::Tab> QTextOption::tabs() const
\value IncludeTrailingSpaces When this option is set, QTextLine::naturalTextWidth() and naturalTextRect() will
return a value that includes the width of trailing spaces in the text; otherwise
this width is excluded.
- \value ShowTabsAndSpaces Visualize spaces with little dots, and tabs with little arrows.
+ \value ShowTabsAndSpaces Visualize spaces with little dots, and tabs with little arrows. Non-breaking spaces are
+ shown differently to breaking spaces.
\value ShowLineAndParagraphSeparators Visualize line and paragraph separators with appropriate symbol characters.
\value ShowDocumentTerminator Visualize the end of the document with a section sign. This enum value was added
in Qt 5.7.