summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/effects/qgraphicseffect.cpp9
-rw-r--r--src/gui/egl/qegl.cpp44
-rw-r--r--src/gui/egl/qegl_p.h1
-rw-r--r--src/gui/egl/qegl_stub.cpp17
-rw-r--r--src/gui/egl/qeglcontext_p.h1
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp8
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp2
-rw-r--r--src/gui/image/qimage.cpp26
-rw-r--r--src/gui/image/qpixmap.cpp23
-rw-r--r--src/gui/image/qpixmap.h2
-rw-r--r--src/gui/image/qpixmap_raster.cpp30
-rw-r--r--src/gui/image/qpixmap_raster_p.h3
-rw-r--r--src/gui/image/qpixmap_x11.cpp182
-rw-r--r--src/gui/image/qpixmap_x11_p.h8
-rw-r--r--src/gui/image/qpixmapdata.cpp17
-rw-r--r--src/gui/image/qpixmapdata_p.h5
-rw-r--r--src/gui/kernel/qapplication_x11.cpp2
-rw-r--r--src/gui/painting/qdrawhelper.cpp17
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp187
-rw-r--r--src/gui/painting/qdrawhelper_neon_asm.S105
-rw-r--r--src/gui/painting/qdrawhelper_neon_p.h5
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp202
-rw-r--r--src/gui/painting/qgraphicssystem.cpp4
-rw-r--r--src/gui/painting/qgraphicssystem_p.h1
-rw-r--r--src/gui/painting/qgraphicssystem_runtime.cpp2
-rw-r--r--src/gui/painting/qgraphicssystem_runtime_p.h2
-rw-r--r--src/gui/painting/qmemrotate.cpp51
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp38
-rw-r--r--src/gui/painting/qpainter.cpp2
-rw-r--r--src/gui/painting/qpathclipper.cpp48
-rw-r--r--src/gui/painting/qpathclipper_p.h4
-rw-r--r--src/gui/text/qtextengine.cpp4
-rw-r--r--src/gui/text/qtextengine_p.h2
-rw-r--r--src/gui/widgets/qmenubar.cpp2
37 files changed, 861 insertions, 206 deletions
diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp
index 5e4e49e..0029017 100644
--- a/src/gui/effects/qgraphicseffect.cpp
+++ b/src/gui/effects/qgraphicseffect.cpp
@@ -488,13 +488,10 @@ void QGraphicsEffect::setEnabled(bool enable)
*/
/*!
- Schedules a redraw of the source. Call this function whenever the source
- needs to be redrawn.
-
- This convenience function is equivalent to calling
- QGraphicsEffectSource::update().
+ Schedules a redraw of the effect. Call this function whenever the effect
+ needs to be redrawn. This function does not trigger a redraw of the source.
- \sa updateBoundingRect(), QGraphicsEffectSource::update()
+ \sa updateBoundingRect()
*/
void QGraphicsEffect::update()
{
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp
index e6ea198..605b1e6 100644
--- a/src/gui/egl/qegl.cpp
+++ b/src/gui/egl/qegl.cpp
@@ -515,6 +515,31 @@ bool QEglContext::swapBuffers(EGLSurface surface)
return ok;
}
+bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region) {
+ QVector<QRect> qrects = region->rects();
+ EGLint *gl_rects;
+ uint count;
+ uint i;
+
+ count = qrects.size();
+ QVarLengthArray <EGLint> arr(4 * count);
+ gl_rects = arr.data();
+ for (i = 0; i < count; i++) {
+ QRect qrect = qrects[i];
+
+ gl_rects[4 * i + 0] = qrect.x();
+ gl_rects[4 * i + 1] = qrect.y();
+ gl_rects[4 * i + 2] = qrect.width();
+ gl_rects[4 * i + 3] = qrect.height();
+ }
+
+ bool ok = QEgl::eglSwapBuffersRegion2NOK(QEgl::display(), surface, count, gl_rects);
+
+ if (!ok)
+ qWarning() << "QEglContext::swapBuffersRegion2NOK():" << QEgl::errorString();
+ return ok;
+}
+
int QEglContext::configAttrib(int name) const
{
EGLint value;
@@ -532,6 +557,9 @@ typedef EGLBoolean (EGLAPIENTRY *_eglDestroyImageKHR)(EGLDisplay, EGLImageKHR);
static _eglCreateImageKHR qt_eglCreateImageKHR = 0;
static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0;
+typedef EGLBoolean (EGLAPIENTRY *_eglSwapBuffersRegion2NOK)(EGLDisplay, EGLSurface, EGLint, const EGLint*);
+
+static _eglSwapBuffersRegion2NOK qt_eglSwapBuffersRegion2NOK = 0;
EGLDisplay QEgl::display()
{
@@ -560,6 +588,10 @@ EGLDisplay QEgl::display()
qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR");
}
#endif
+
+ if (QEgl::hasExtension("EGL_NOK_swap_region2")) {
+ qt_eglSwapBuffersRegion2NOK = (_eglSwapBuffersRegion2NOK) eglGetProcAddress("eglSwapBuffersRegion2NOK");
+ }
}
return dpy;
@@ -591,6 +623,18 @@ EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return 0;
}
+EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects)
+{
+ if (qt_eglSwapBuffersRegion2NOK)
+ return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects);
+
+ QEgl::display(); // Initialises function pointers
+ if (qt_eglSwapBuffersRegion2NOK)
+ return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects);
+
+ qWarning("QEgl::eglSwapBuffersRegion2NOK() called but EGL_NOK_swap_region2 extension not present");
+ return 0;
+}
#ifndef Q_WS_X11
EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties)
diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h
index 4fc1338..c214e88 100644
--- a/src/gui/egl/qegl_p.h
+++ b/src/gui/egl/qegl_p.h
@@ -224,6 +224,7 @@ namespace QEgl {
// Extension functions
Q_GUI_EXPORT EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
Q_GUI_EXPORT EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img);
+ Q_GUI_EXPORT EGLBoolean eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects);
#ifdef Q_WS_X11
Q_GUI_EXPORT VisualID getCompatibleVisualId(EGLConfig config);
diff --git a/src/gui/egl/qegl_stub.cpp b/src/gui/egl/qegl_stub.cpp
index 86a7aab..1adb56c 100644
--- a/src/gui/egl/qegl_stub.cpp
+++ b/src/gui/egl/qegl_stub.cpp
@@ -176,6 +176,14 @@ bool QEglContext::swapBuffers(EGLSurface surface)
return false;
}
+bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region)
+{
+ Q_UNUSED(surface)
+ Q_UNUSED(region)
+ NOEGL
+ return false;
+}
+
int QEglContext::configAttrib(int name) const
{
Q_UNUSED(name)
@@ -208,6 +216,15 @@ EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return 0;
}
+EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects)
+{
+ Q_UNUSED(dpy);
+ Q_UNUSED(surface);
+ Q_UNUSED(count);
+ Q_UNUSED(rects);
+ NOEGL
+ return 0;
+}
#ifndef Q_WS_X11
EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties)
diff --git a/src/gui/egl/qeglcontext_p.h b/src/gui/egl/qeglcontext_p.h
index ccde00d..cae8164 100644
--- a/src/gui/egl/qeglcontext_p.h
+++ b/src/gui/egl/qeglcontext_p.h
@@ -84,6 +84,7 @@ public:
bool doneCurrent();
bool lazyDoneCurrent();
bool swapBuffers(EGLSurface surface);
+ bool swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region);
int configAttrib(int name) const;
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 8a419b4..51dc543 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -411,6 +411,11 @@
these notifications are disabled by default. You must enable this flag
to receive notifications for scene position changes. This flag was
introduced in Qt 4.6.
+
+ \omitvalue ItemStopsClickFocusPropagation \omit The item stops propagating
+ click focus to items underneath when being clicked on. This flag
+ allows you create a non-focusable item that can be clicked on without
+ changing the focus. \endomit
*/
/*!
@@ -11435,6 +11440,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
case QGraphicsItem::ItemSendsScenePositionChanges:
str = "ItemSendsScenePositionChanges";
break;
+ case QGraphicsItem::ItemStopsClickFocusPropagation:
+ str = "ItemStopsClickFocusPropagation";
+ break;
}
debug << str;
return debug;
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index d7d5332..3c193cd 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -106,7 +106,8 @@ public:
ItemNegativeZStacksBehindParent = 0x2000,
ItemIsPanel = 0x4000,
ItemIsFocusScope = 0x8000, // internal
- ItemSendsScenePositionChanges = 0x10000
+ ItemSendsScenePositionChanges = 0x10000,
+ ItemStopsClickFocusPropagation = 0x20000
// NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
};
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index bde6e7d..f9f5d3d 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -556,7 +556,7 @@ public:
quint32 dirtyChildrenBoundingRect : 1;
// Packed 32 bits
- quint32 flags : 17;
+ quint32 flags : 18;
quint32 paintedViewBoundingRectsNeedRepaint : 1;
quint32 dirtySceneTransform : 1;
quint32 geometryChanged : 1;
@@ -571,9 +571,9 @@ public:
quint32 notifyBoundingRectChanged : 1;
quint32 notifyInvalidated : 1;
quint32 mouseSetsFocus : 1;
- quint32 explicitActivate : 1;
// New 32 bits
+ quint32 explicitActivate : 1;
quint32 wantsActive : 1;
quint32 holesInSiblingIndex : 1;
quint32 sequentialOrdering : 1;
@@ -582,7 +582,7 @@ public:
quint32 pendingPolish : 1;
quint32 mayHaveChildWithGraphicsEffect : 1;
quint32 isDeclarativeItem : 1;
- quint32 padding : 24;
+ quint32 padding : 23;
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index e5264da..4bc7f4c 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -1335,6 +1335,8 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
break;
}
}
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
+ break;
if (item->isPanel())
break;
}
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index bb8a994..79f266d 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -2338,6 +2338,12 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ if (data->colortable.size() == 0) {
+ data->colortable.resize(256);
+ for (int i = 0; i < 256; ++i)
+ data->colortable[i] = qRgb(i, i, i);
+ }
+ const int tableSize = data->colortable.size() - 1;
for (int i = 0; i < data->height; ++i) {
src_data -= src_pad;
@@ -2345,7 +2351,7 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
for (int pixI = 0; pixI < width; ++pixI) {
--src_data;
--dest_data;
- const uint pixel = data->colortable[*src_data];
+ const uint pixel = data->colortable[qMin<int>(tableSize, *src_data)];
*dest_data = (quint32) PREMUL(pixel);
}
}
@@ -2377,6 +2383,12 @@ static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversio
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
const int dest_pad = (dst_bytes_per_line >> 2) - width;
+ if (data->colortable.size() == 0) {
+ data->colortable.resize(256);
+ for (int i = 0; i < 256; ++i)
+ data->colortable[i] = qRgb(i, i, i);
+ }
+ const int tableSize = data->colortable.size() - 1;
for (int i = 0; i < data->height; ++i) {
src_data -= src_pad;
@@ -2384,7 +2396,7 @@ static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversio
for (int pixI = 0; pixI < width; ++pixI) {
--src_data;
--dest_data;
- *dest_data = (quint32) data->colortable[*src_data];
+ *dest_data = (quint32) data->colortable[qMin<int>(tableSize, *src_data)];
}
}
@@ -2415,6 +2427,12 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
const int width = data->width;
const int src_pad = data->bytes_per_line - width;
const int dest_pad = (dst_bytes_per_line >> 1) - width;
+ if (data->colortable.size() == 0) {
+ data->colortable.resize(256);
+ for (int i = 0; i < 256; ++i)
+ data->colortable[i] = qRgb(i, i, i);
+ }
+ const int tableSize = data->colortable.size() - 1;
for (int i = 0; i < data->height; ++i) {
src_data -= src_pad;
@@ -2422,7 +2440,7 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
for (int pixI = 0; pixI < width; ++pixI) {
--src_data;
--dest_data;
- const uint pixel = data->colortable[*src_data];
+ const uint pixel = data->colortable[qMin<int>(tableSize, *src_data)];
*dest_data = qt_colorConvert<quint16, quint32>(pixel, 0);
}
}
@@ -4061,7 +4079,7 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
}
break;
case Format_Indexed8:
- if (index_or_rgb > (uint)d->colortable.size()) {
+ if (index_or_rgb >= (uint)d->colortable.size()) {
qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
return;
}
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index fd2c139..ef9be8f 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -2018,7 +2018,7 @@ void QPixmap::detach()
the color table. If this is too expensive an operation, you can
use QBitmap::fromImage() instead.
- \sa toImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
+ \sa fromImageReader(), toImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
*/
QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
{
@@ -2033,6 +2033,27 @@ QPixmap QPixmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
}
/*!
+ \fn QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags)
+
+ Create a QPixmap from an image read directly from an \a imageReader.
+ The \a flags argument is a bitwise-OR of the \l{Qt::ImageConversionFlags}.
+ Passing 0 for \a flags sets all the default options.
+
+ On some systems, reading an image directly to QPixmap can use less memory than
+ reading a QImage to convert it to QPixmap.
+
+ \sa fromImage(), toImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
+*/
+QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags)
+{
+ QGraphicsSystem *gs = QApplicationPrivate::graphicsSystem();
+ QScopedPointer<QPixmapData> data(gs ? gs->createPixmapData(QPixmapData::PixmapType)
+ : QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixmapType));
+ data->fromImageReader(imageReader, flags);
+ return QPixmap(data.take());
+}
+
+/*!
\fn QPixmap QPixmap::grabWindow(WId window, int x, int y, int
width, int height)
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h
index 82546da..64ca8a3 100644
--- a/src/gui/image/qpixmap.h
+++ b/src/gui/image/qpixmap.h
@@ -62,6 +62,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QImageWriter;
+class QImageReader;
class QColor;
class QVariant;
class QX11Info;
@@ -134,6 +135,7 @@ public:
QImage toImage() const;
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags = Qt::AutoColor);
+ static QPixmap fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags = Qt::AutoColor);
bool load(const QString& fileName, const char *format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor);
bool loadFromData(const uchar *buf, uint len, const char* format = 0, Qt::ImageConversionFlags flags = Qt::AutoColor);
diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index 13c03a1..53f3559 100644
--- a/src/gui/image/qpixmap_raster.cpp
+++ b/src/gui/image/qpixmap_raster.cpp
@@ -152,9 +152,25 @@ void QRasterPixmapData::fromImage(const QImage &sourceImage,
createPixmapForImage(image, flags, /* inplace = */false);
}
+void QRasterPixmapData::fromImageReader(QImageReader *imageReader,
+ Qt::ImageConversionFlags flags)
+{
+ Q_UNUSED(flags);
+ QImage image = imageReader->read();
+ if (image.isNull())
+ return;
+
+ createPixmapForImage(image, flags, /* inplace = */true);
+}
+
// from qwindowsurface.cpp
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
+void QRasterPixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ fromImage(data->toImage(rect).copy(), Qt::NoOpaqueDetection);
+}
+
bool QRasterPixmapData::scroll(int dx, int dy, const QRect &rect)
{
if (!image.isNull())
@@ -289,6 +305,20 @@ QImage QRasterPixmapData::toImage() const
return image;
}
+QImage QRasterPixmapData::toImage(const QRect &rect) const
+{
+ if (rect.isNull())
+ return image;
+
+ QRect clipped = rect.intersected(QRect(0, 0, w, h));
+ if (d % 8 == 0)
+ return QImage(image.scanLine(clipped.y()) + clipped.x() * (d / 8),
+ clipped.width(), clipped.height(),
+ image.bytesPerLine(), image.format());
+ else
+ return image.copy(clipped);
+}
+
void QRasterPixmapData::setAlphaChannel(const QPixmap &alphaChannel)
{
image.setAlphaChannel(alphaChannel.toImage());
diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h
index d7e3f85..36a9b2f 100644
--- a/src/gui/image/qpixmap_raster_p.h
+++ b/src/gui/image/qpixmap_raster_p.h
@@ -74,13 +74,16 @@ public:
void fromFile(const QString &filename, Qt::ImageConversionFlags flags);
bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags);
void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
+ void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags);
+ void copy(const QPixmapData *data, const QRect &rect);
bool scroll(int dx, int dy, const QRect &rect);
void fill(const QColor &color);
void setMask(const QBitmap &mask);
bool hasAlphaChannel() const;
void setAlphaChannel(const QPixmap &alphaChannel);
QImage toImage() const;
+ QImage toImage(const QRect &rect) const;
QPaintEngine* paintEngine() const;
QImage* buffer();
diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp
index e8dc5ae..3d9c363 100644
--- a/src/gui/image/qpixmap_x11.cpp
+++ b/src/gui/image/qpixmap_x11.cpp
@@ -1458,6 +1458,105 @@ int QX11PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
}
}
+struct QXImageWrapper
+{
+ XImage *xi;
+};
+
+bool QX11PixmapData::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ // ARGB32_Premultiplied
+ if (picture && depth() == 32)
+ return true;
+
+ Visual *visual = (Visual *)xinfo.visual();
+
+ // RGB32
+ if (depth() == 24 && xi->bits_per_pixel == 32 && visual->red_mask == 0xff0000
+ && visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
+ return true;
+
+ // RGB16
+ if (depth() == 16 && xi->bits_per_pixel == 16 && visual->red_mask == 0xf800
+ && visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
+ return true;
+
+ return false;
+}
+
+QImage QX11PixmapData::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const
+{
+ XImage *xi = xiWrapper.xi;
+
+ QImage::Format format = QImage::Format_ARGB32_Premultiplied;
+ if (depth() == 24)
+ format = QImage::Format_RGB32;
+ else if (depth() == 16)
+ format = QImage::Format_RGB16;
+
+ QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format);
+ // take ownership
+ image.data_ptr()->own_data = true;
+ xi->data = 0;
+
+ // we may have to swap the byte order
+ if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
+ || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
+ {
+ for (int i=0; i < image.height(); i++) {
+ if (depth() == 16) {
+ ushort *p = (ushort*)image.scanLine(i);
+ ushort *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
+ p++;
+ }
+ } else {
+ uint *p = (uint*)image.scanLine(i);
+ uint *end = p + image.width();
+ while (p < end) {
+ *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
+ p++;
+ }
+ }
+ }
+ }
+
+ // fix-up alpha channel
+ if (format == QImage::Format_RGB32) {
+ QRgb *p = (QRgb *)image.bits();
+ for (int y = 0; y < xi->height; ++y) {
+ for (int x = 0; x < xi->width; ++x)
+ p[x] |= 0xff000000;
+ p += xi->bytes_per_line / 4;
+ }
+ }
+
+ XDestroyImage(xi);
+ return image;
+}
+
+QImage QX11PixmapData::toImage(const QRect &rect) const
+{
+ QXImageWrapper xiWrapper;
+ xiWrapper.xi = XGetImage(X11->display, hd, rect.x(), rect.y(), rect.width(), rect.height(),
+ AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap);
+
+ Q_CHECK_PTR(xiWrapper.xi);
+ if (!xiWrapper.xi)
+ return QImage();
+
+ if (canTakeQImageFromXImage(xiWrapper))
+ return takeQImageFromXImage(xiWrapper);
+
+ QImage image = toImage(xiWrapper, rect);
+ qSafeXDestroyImage(xiWrapper.xi);
+ return image;
+}
+
/*!
Converts the pixmap to a QImage. Returns a null image if the
conversion fails.
@@ -1475,6 +1574,13 @@ int QX11PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
QImage QX11PixmapData::toImage() const
{
+ return toImage(QRect(0, 0, w, h));
+}
+
+QImage QX11PixmapData::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const
+{
+ XImage *xi = xiWrapper.xi;
+
int d = depth();
Visual *visual = (Visual *)xinfo.visual();
bool trucol = (visual->c_class >= TrueColor) && d > 1;
@@ -1492,59 +1598,21 @@ QImage QX11PixmapData::toImage() const
format = QImage::Format_RGB32;
}
- XImage *xi = XGetImage(X11->display, hd, 0, 0, w, h, AllPlanes,
- (d == 1) ? XYPixmap : ZPixmap);
-
- Q_CHECK_PTR(xi);
- if (!xi)
- return QImage();
-
- if (picture && depth() == 32) {
- QImage image(w, h, QImage::Format_ARGB32_Premultiplied);
- memcpy(image.bits(), xi->data, xi->bytes_per_line * xi->height);
-
- // we may have to swap the byte order
- if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst)
- || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst))
- {
- for (int i=0; i < image.height(); i++) {
- uint *p = (uint*)image.scanLine(i);
- uint *end = p + image.width();
- if ((xi->byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian)
- || (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
- while (p < end) {
- *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
- | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
- p++;
- }
- } else if (xi->byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- while (p < end) {
- *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff)
- | ((*p ) & 0xff00ff00);
- p++;
- }
- }
- }
- }
-
- // throw away image data
- qSafeXDestroyImage(xi);
-
- return image;
- }
-
if (d == 1 && xi->bitmap_bit_order == LSBFirst)
format = QImage::Format_MonoLSB;
if (x11_mask && format == QImage::Format_RGB32)
format = QImage::Format_ARGB32;
- QImage image(w, h, format);
+ QImage image(xi->width, xi->height, format);
if (image.isNull()) // could not create image
return image;
QImage alpha;
if (x11_mask) {
- alpha = mask().toImage();
+ if (rect.contains(QRect(0, 0, w, h)))
+ alpha = mask().toImage();
+ else
+ alpha = mask().toImage().copy(rect);
}
bool ale = alpha.format() == QImage::Format_MonoLSB;
@@ -1587,11 +1655,11 @@ QImage QX11PixmapData::toImage() const
if (bppc > 8 && xi->byte_order == LSBFirst)
bppc++;
- for (int y = 0; y < h; ++y) {
+ for (int y = 0; y < xi->height; ++y) {
uchar* asrc = x11_mask ? alpha.scanLine(y) : 0;
dst = (QRgb *)image.scanLine(y);
src = (uchar *)xi->data + xi->bytes_per_line*y;
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
switch (bppc) {
case 8:
pixel = *src++;
@@ -1621,8 +1689,8 @@ QImage QX11PixmapData::toImage() const
src += 4;
break;
default: // should not really happen
- x = w; // leave loop
- y = h;
+ x = xi->width; // leave loop
+ y = xi->height;
pixel = 0; // eliminate compiler warning
qWarning("QPixmap::convertToImage: Invalid depth %d", bppc);
}
@@ -1660,7 +1728,7 @@ QImage QX11PixmapData::toImage() const
} else if (xi->bits_per_pixel == d) { // compatible depth
char *xidata = xi->data; // copy each scanline
int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
- for (int y=0; y<h; y++) {
+ for (int y=0; y<xi->height; y++) {
memcpy(image.scanLine(y), xidata, bpl);
xidata += xi->bytes_per_line;
}
@@ -1686,17 +1754,17 @@ QImage QX11PixmapData::toImage() const
bpl = image.bytesPerLine();
if (x11_mask) { // which pixels are used?
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
uchar* asrc = alpha.scanLine(i);
p = image.scanLine(i);
if (ale) {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (asrc[x >> 3] & (1 << (x & 7)))
use[*p] = 1;
++p;
}
} else {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (asrc[x >> 3] & (0x80 >> (x & 7)))
use[*p] = 1;
++p;
@@ -1704,7 +1772,7 @@ QImage QX11PixmapData::toImage() const
}
}
} else {
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
p = image.scanLine(i);
end = p + bpl;
while (p < end)
@@ -1716,7 +1784,7 @@ QImage QX11PixmapData::toImage() const
if (use[i])
pix[i] = ncols++;
}
- for (int i = 0; i < h; i++) { // translate pixels
+ for (int i = 0; i < xi->height; i++) { // translate pixels
p = image.scanLine(i);
end = p + bpl;
while (p < end) {
@@ -1736,17 +1804,17 @@ QImage QX11PixmapData::toImage() const
// use first pixel in image (as good as any).
trans = image.scanLine(0)[0];
}
- for (int i = 0; i < h; i++) {
+ for (int i = 0; i < xi->height; i++) {
uchar* asrc = alpha.scanLine(i);
p = image.scanLine(i);
if (ale) {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (!(asrc[x >> 3] & (1 << (x & 7))))
*p = trans;
++p;
}
} else {
- for (int x = 0; x < w; x++) {
+ for (int x = 0; x < xi->width; x++) {
if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
*p = trans;
++p;
@@ -1764,8 +1832,6 @@ QImage QX11PixmapData::toImage() const
}
}
- qSafeXDestroyImage(xi);
-
return image;
}
diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h
index 7575838..821fb69 100644
--- a/src/gui/image/qpixmap_x11_p.h
+++ b/src/gui/image/qpixmap_x11_p.h
@@ -62,6 +62,8 @@ QT_BEGIN_NAMESPACE
class QX11PaintEngine;
+struct QXImageWrapper;
+
class Q_GUI_EXPORT QX11PixmapData : public QPixmapData
{
public:
@@ -87,6 +89,7 @@ public:
QPixmap transformed(const QTransform &transform,
Qt::TransformationMode mode) const;
QImage toImage() const;
+ QImage toImage(const QRect &rect) const;
QPaintEngine* paintEngine() const;
Qt::HANDLE handle() const { return hd; }
@@ -116,10 +119,15 @@ private:
void release();
+ QImage toImage(const QXImageWrapper &xi, const QRect &rect) const;
+
QBitmap mask_to_bitmap(int screen) const;
static Qt::HANDLE bitmap_to_mask(const QBitmap &, int screen);
void bitmapFromImage(const QImage &image);
+ bool canTakeQImageFromXImage(const QXImageWrapper &xi) const;
+ QImage takeQImageFromXImage(const QXImageWrapper &xi) const;
+
Qt::HANDLE hd;
enum Flag {
diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp
index 31ca909..ef1f6c4 100644
--- a/src/gui/image/qpixmapdata.cpp
+++ b/src/gui/image/qpixmapdata.cpp
@@ -124,6 +124,13 @@ static QImage makeBitmapCompliantIfNeeded(QPixmapData *d, const QImage &image, Q
return image;
}
+void QPixmapData::fromImageReader(QImageReader *imageReader,
+ Qt::ImageConversionFlags flags)
+{
+ const QImage image = imageReader->read();
+ fromImage(image, flags);
+}
+
bool QPixmapData::fromFile(const QString &fileName, const char *format,
Qt::ImageConversionFlags flags)
{
@@ -146,7 +153,7 @@ bool QPixmapData::fromData(const uchar *buf, uint len, const char *format, Qt::I
void QPixmapData::copy(const QPixmapData *data, const QRect &rect)
{
- fromImage(data->toImage().copy(rect), Qt::NoOpaqueDetection);
+ fromImage(data->toImage(rect), Qt::NoOpaqueDetection);
}
bool QPixmapData::scroll(int dx, int dy, const QRect &rect)
@@ -255,6 +262,14 @@ void QPixmapData::setSerialNumber(int serNo)
ser_no = serNo;
}
+QImage QPixmapData::toImage(const QRect &rect) const
+{
+ if (rect.contains(QRect(0, 0, w, h)))
+ return toImage();
+ else
+ return toImage().copy(rect);
+}
+
QImage* QPixmapData::buffer()
{
return 0;
diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h
index 60ed26a..ec62b0b 100644
--- a/src/gui/image/qpixmapdata_p.h
+++ b/src/gui/image/qpixmapdata_p.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
+class QImageReader;
+
class Q_GUI_EXPORT QPixmapData
{
public:
@@ -83,6 +85,8 @@ public:
virtual void resize(int width, int height) = 0;
virtual void fromImage(const QImage &image,
Qt::ImageConversionFlags flags) = 0;
+ virtual void fromImageReader(QImageReader *imageReader,
+ Qt::ImageConversionFlags flags);
virtual bool fromFile(const QString &filename, const char *format,
Qt::ImageConversionFlags flags);
@@ -102,6 +106,7 @@ public:
virtual void setAlphaChannel(const QPixmap &alphaChannel);
virtual QPixmap alphaChannel() const;
virtual QImage toImage() const = 0;
+ virtual QImage toImage(const QRect &rect) const;
virtual QPaintEngine* paintEngine() const = 0;
inline int serialNumber() const { return ser_no; }
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 3664743..e4d9848 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -2155,7 +2155,7 @@ void qt_init(QApplicationPrivate *priv, int,
X11->fc_scale = fc_scale;
for (int s = 0; s < ScreenCount(X11->display); ++s) {
int subpixel = FC_RGBA_UNKNOWN;
-#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
+#if !defined(QT_NO_XRENDER) && (RENDER_MAJOR > 0 || RENDER_MINOR >= 6)
if (X11->use_xrender) {
int rsp = XRenderQuerySubpixelOrder(X11->display, s);
switch (rsp) {
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index bfa1136..ca9556b 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -5014,7 +5014,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
length -= copy_image_width;
copy_image_width *= 2;
}
- qt_memconvert(dest, src, length);
+ if (length > 0)
+ qt_memconvert(dest, src, length);
} else {
while (length) {
int l = qMin(image_width - sx, length);
@@ -7817,6 +7818,15 @@ void qInitDrawhelperAsm()
#ifdef QT_HAVE_SSE2
if (features & SSE2) {
+ extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels,
+ const uint *srcPixels,
+ int length,
+ uint const_alpha);
+ extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha);
+
+ functionForModeAsm[0] = comp_func_SourceOver_sse2;
+ functionForModeSolidAsm[0] = comp_func_solid_SourceOver_sse2;
+
extern void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
int w, int h,
@@ -7826,7 +7836,6 @@ void qInitDrawhelperAsm()
int w, int h,
int const_alpha);
-
qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
@@ -7890,8 +7899,12 @@ void qInitDrawhelperAsm()
qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon;
functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon;
+ functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
+
+ qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
+ qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
}
#endif
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index ee5f24a..03fe075 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -579,6 +579,193 @@ void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer, int x, int
}
}
+void QT_FASTCALL comp_func_solid_SourceOver_neon(uint *destPixels, int length, uint color, uint const_alpha)
+{
+ if ((const_alpha & qAlpha(color)) == 255) {
+ QT_MEMFILL_UINT(destPixels, length, color);
+ } else {
+ if (const_alpha != 255)
+ color = BYTE_MUL(color, const_alpha);
+
+ const quint32 minusAlphaOfColor = qAlpha(~color);
+ int x = 0;
+
+ uint32_t *dst = (uint32_t *) destPixels;
+ const uint32x4_t colorVector = vdupq_n_u32(color);
+ uint16x8_t half = vdupq_n_u16(0x80);
+ const uint16x8_t minusAlphaOfColorVector = vdupq_n_u16(minusAlphaOfColor);
+
+ for (; x < length-3; x += 4) {
+ uint32x4_t dstVector = vld1q_u32(&dst[x]);
+
+ const uint8x16_t dst8 = vreinterpretq_u8_u32(dstVector);
+
+ const uint8x8_t dst8_low = vget_low_u8(dst8);
+ const uint8x8_t dst8_high = vget_high_u8(dst8);
+
+ const uint16x8_t dst16_low = vmovl_u8(dst8_low);
+ const uint16x8_t dst16_high = vmovl_u8(dst8_high);
+
+ const uint16x8_t result16_low = qvbyte_mul_u16(dst16_low, minusAlphaOfColorVector, half);
+ const uint16x8_t result16_high = qvbyte_mul_u16(dst16_high, minusAlphaOfColorVector, half);
+
+ const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low));
+ const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high));
+
+ uint32x4_t blendedPixels = vcombine_u32(result32_low, result32_high);
+ uint32x4_t colorPlusBlendedPixels = vaddq_u32(colorVector, blendedPixels);
+ vst1q_u32(&dst[x], colorPlusBlendedPixels);
+ }
+
+ for (;x < length; ++x)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
+ }
+}
+
+static const int tileSize = 32;
+
+extern "C" void qt_rotate90_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count);
+
+void qt_memrotate90_16_neon(const uchar *srcPixels, int w, int h, int sstride, uchar *destPixels, int dstride)
+{
+ const ushort *src = (const ushort *)srcPixels;
+ ushort *dest = (ushort *)destPixels;
+
+ sstride /= sizeof(ushort);
+ dstride /= sizeof(ushort);
+
+ const int pack = sizeof(quint32) / sizeof(ushort);
+ const int unaligned =
+ qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(ushort)), uint(h));
+ const int restX = w % tileSize;
+ const int restY = (h - unaligned) % tileSize;
+ const int unoptimizedY = restY % pack;
+ const int numTilesX = w / tileSize + (restX > 0);
+ const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
+
+ for (int tx = 0; tx < numTilesX; ++tx) {
+ const int startx = w - tx * tileSize - 1;
+ const int stopx = qMax(startx - tileSize, 0);
+
+ if (unaligned) {
+ for (int x = startx; x >= stopx; --x) {
+ ushort *d = dest + (w - x - 1) * dstride;
+ for (int y = 0; y < unaligned; ++y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+
+ for (int ty = 0; ty < numTilesY; ++ty) {
+ const int starty = ty * tileSize + unaligned;
+ const int stopy = qMin(starty + tileSize, h - unoptimizedY);
+
+ int x = startx;
+ // qt_rotate90_16_neon writes to eight rows, four pixels at a time
+ for (; x >= stopx + 7; x -= 8) {
+ ushort *d = dest + (w - x - 1) * dstride + starty;
+ const ushort *s = &src[starty * sstride + x - 7];
+ qt_rotate90_16_neon(d, s, sstride * 2, dstride * 2, stopy - starty);
+ }
+
+ for (; x >= stopx; --x) {
+ quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride + starty);
+ for (int y = starty; y < stopy; y += pack) {
+ quint32 c = src[y * sstride + x];
+ for (int i = 1; i < pack; ++i) {
+ const int shift = (sizeof(int) * 8 / pack * i);
+ const ushort color = src[(y + i) * sstride + x];
+ c |= color << shift;
+ }
+ *d++ = c;
+ }
+ }
+ }
+
+ if (unoptimizedY) {
+ const int starty = h - unoptimizedY;
+ for (int x = startx; x >= stopx; --x) {
+ ushort *d = dest + (w - x - 1) * dstride + starty;
+ for (int y = starty; y < h; ++y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+ }
+}
+
+extern "C" void qt_rotate270_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count);
+
+void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h,
+ int sstride,
+ uchar *destPixels, int dstride)
+{
+ const ushort *src = (const ushort *)srcPixels;
+ ushort *dest = (ushort *)destPixels;
+
+ sstride /= sizeof(ushort);
+ dstride /= sizeof(ushort);
+
+ const int pack = sizeof(quint32) / sizeof(ushort);
+ const int unaligned =
+ qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(ushort)), uint(h));
+ const int restX = w % tileSize;
+ const int restY = (h - unaligned) % tileSize;
+ const int unoptimizedY = restY % pack;
+ const int numTilesX = w / tileSize + (restX > 0);
+ const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
+
+ for (int tx = 0; tx < numTilesX; ++tx) {
+ const int startx = tx * tileSize;
+ const int stopx = qMin(startx + tileSize, w);
+
+ if (unaligned) {
+ for (int x = startx; x < stopx; ++x) {
+ ushort *d = dest + x * dstride;
+ for (int y = h - 1; y >= h - unaligned; --y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+
+ for (int ty = 0; ty < numTilesY; ++ty) {
+ const int starty = h - 1 - unaligned - ty * tileSize;
+ const int stopy = qMax(starty - tileSize, unoptimizedY);
+
+ int x = startx;
+ // qt_rotate90_16_neon writes to eight rows, four pixels at a time
+ for (; x < stopx - 7; x += 8) {
+ ushort *d = dest + x * dstride + h - 1 - starty;
+ const ushort *s = &src[starty * sstride + x];
+ qt_rotate90_16_neon(d + 7 * dstride, s, -sstride * 2, -dstride * 2, starty - stopy);
+ }
+
+ for (; x < stopx; ++x) {
+ quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
+ + h - 1 - starty);
+ for (int y = starty; y > stopy; y -= pack) {
+ quint32 c = src[y * sstride + x];
+ for (int i = 1; i < pack; ++i) {
+ const int shift = (sizeof(int) * 8 / pack * i);
+ const ushort color = src[(y - i) * sstride + x];
+ c |= color << shift;
+ }
+ *d++ = c;
+ }
+ }
+ }
+ if (unoptimizedY) {
+ const int starty = unoptimizedY - 1;
+ for (int x = startx; x < stopx; ++x) {
+ ushort *d = dest + x * dstride + h - 1 - starty;
+ for (int y = starty; y >= 0; --y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+ }
+}
+
QT_END_NAMESPACE
#endif // QT_HAVE_NEON
diff --git a/src/gui/painting/qdrawhelper_neon_asm.S b/src/gui/painting/qdrawhelper_neon_asm.S
index 9992817..d9cdc36 100644
--- a/src/gui/painting/qdrawhelper_neon_asm.S
+++ b/src/gui/painting/qdrawhelper_neon_asm.S
@@ -190,3 +190,108 @@ blend_8_pixels_rgb16_on_rgb16_neon:
bx lr
.endfunc
+
+/* void qt_rotate90_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count) */
+ .func qt_rotate90_16_neon
+ .global qt_rotate90_16_neon
+ /* For ELF format also set function visibility to hidden */
+#ifdef __ELF__
+ .hidden qt_rotate90_16_neon
+ .type qt_rotate90_16_neon, %function
+#endif
+qt_rotate90_16_neon:
+ push { r4-r11, lr }
+ ldr r5, [sp, #(9*4)]
+
+ /* The preloads are the key to getting good performance */
+ pld [r1]
+
+ mov r4, r5, asr #2
+ add r6, r0, r3
+ add r7, r6, r3
+
+ add r8, r7, r3
+ add r9, r8, r3
+
+ pld [r1, r2]
+
+ add r10, r9, r3
+ add r11, r10, r3
+
+ add r3, r3, r11
+ and r5, r5, #3
+
+ pld [r1, r2, lsl #1]
+
+ cmp r4, #0
+ beq .rotate90_16_tail
+
+.rotate90_16_loop:
+ vld1.16 { q8 }, [r1], r2
+
+ pld [r1, r2, lsl #1]
+
+ vld1.16 { q9 }, [r1], r2
+ vld1.16 { q10 }, [r1], r2
+ vld1.16 { q11 }, [r1], r2
+
+ pld [r1]
+
+ /* Could have used four quad-word zips instead,
+ but those take three cycles as opposed to one. */
+ vzip.16 d16, d20
+ vzip.16 d17, d21
+
+ vzip.16 d18, d22
+
+ pld [r1, r2]
+
+ vzip.16 d19, d23
+
+ vzip.16 d16, d18
+ vzip.16 d17, d19
+
+ pld [r1, r2, lsl #1]
+
+ vzip.16 d20, d22
+ vzip.16 d21, d23
+
+ vst1.16 { d23 }, [r0]!
+ vst1.16 { d21 }, [r6]!
+ vst1.16 { d19 }, [r7]!
+ vst1.16 { d17 }, [r8]!
+ vst1.16 { d22 }, [r9]!
+ vst1.16 { d20 }, [r10]!
+ vst1.16 { d18 }, [r11]!
+ vst1.16 { d16 }, [r3]!
+
+ sub r4, r4, #1
+ cmp r4, #0
+ bne .rotate90_16_loop
+ b .rotate90_16_tail
+
+.rotate90_16_tail_loop:
+ sub r5, r5, #2
+
+ vld1.16 { q8 }, [r1], r2
+ vld1.16 { q9 }, [r1], r2
+
+ vzip.16 d16, d18
+ vzip.16 d17, d19
+
+ vst1.32 { d19[1] }, [r0]!
+ vst1.32 { d19[0] }, [r6]!
+ vst1.32 { d17[1] }, [r7]!
+ vst1.32 { d17[0] }, [r8]!
+ vst1.32 { d18[1] }, [r9]!
+ vst1.32 { d18[0] }, [r10]!
+ vst1.32 { d16[1] }, [r11]!
+ vst1.32 { d16[0] }, [r3]!
+
+.rotate90_16_tail:
+ cmp r5, #0
+ bgt .rotate90_16_tail_loop
+
+ pop { r4-r11, pc }
+
+ .endfunc
diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h
index d6a4509..cd2dbfc 100644
--- a/src/gui/painting/qdrawhelper_neon_p.h
+++ b/src/gui/painting/qdrawhelper_neon_p.h
@@ -120,6 +120,9 @@ void qt_transform_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl,
const QTransform &targetRectTransform,
int const_alpha);
+void qt_memrotate90_16_neon(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
+void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
+
uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer,
QRasterBuffer *rasterBuffer,
int x, int y, int length);
@@ -127,6 +130,8 @@ uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer,
void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer,
int x, int y, const uint *buffer, int length);
+void QT_FASTCALL comp_func_solid_SourceOver_neon(uint *destPixels, int length, uint color, uint const_alpha);
+
#endif // QT_HAVE_NEON
QT_END_NAMESPACE
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index acf765c..97c78bb 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -152,6 +152,7 @@ typedef void (*SrcOverTransformFunc)(uchar *destPixels, int dbpl,
const QTransform &targetRectTransform,
int const_alpha);
+typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
struct DrawHelper {
ProcessSpans blendColor;
@@ -165,6 +166,7 @@ struct DrawHelper {
extern SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats];
+extern MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3];
extern DrawHelper qDrawHelper[QImage::NImageFormats];
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 6ac64d3..6cd8688 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -126,13 +126,100 @@ QT_BEGIN_NAMESPACE
result = _mm_or_si128(finalAG, finalRB); \
}
+// Basically blend src over dst with the const alpha defined as constAlphaVector.
+// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
+//const __m128i nullVector = _mm_set1_epi32(0);
+//const __m128i half = _mm_set1_epi16(0x80);
+//const __m128i one = _mm_set1_epi16(0xff);
+//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+//const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+//
+// The computation being done is:
+// result = s + d * (1-alpha)
+// with shortcuts if fully opaque or fully transparent.
+#define BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
+ int x = 0; \
+ for (; x < length-3; x += 4) { \
+ const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
+ /* all opaque */ \
+ _mm_storeu_si128((__m128i *)&dst[x], srcVector); \
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
+ /* not fully transparent */ \
+ /* extract the alpha channel on 2 x 16 bits */ \
+ /* so we have room for the multiplication */ \
+ /* each 32 bits will be in the form 0x00AA00AA */ \
+ /* with A being the 1 - alpha */ \
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ \
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ \
+ /* result = s + d * (1-alpha) */\
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_storeu_si128((__m128i *)&dst[x], result); \
+ } \
+ } \
+ for (; x < length; ++x) { \
+ uint s = src[x]; \
+ if (s >= 0xff000000) \
+ dst[x] = s; \
+ else if (s != 0) \
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
+ } \
+}
+
+// Basically blend src over dst with the const alpha defined as constAlphaVector.
+// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
+//const __m128i nullVector = _mm_set1_epi32(0);
+//const __m128i half = _mm_set1_epi16(0x80);
+//const __m128i one = _mm_set1_epi16(0xff);
+//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+//
+// The computation being done is:
+// dest = (s + d * sia) * ca + d * cia
+// = s * ca + d * (sia * ca + cia)
+// = s * ca + d * (1 - sa*ca)
+#define BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, length, nullVector, half, one, colorMask, constAlphaVector) \
+{ \
+ int x = 0; \
+ for (; x < length-3; x += 4) { \
+ __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) { \
+ BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half); \
+\
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ \
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ \
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_storeu_si128((__m128i *)&dst[x], result); \
+ } \
+ } \
+ for (; x < length; ++x) { \
+ quint32 s = src[x]; \
+ if (s != 0) { \
+ s = BYTE_MUL(s, const_alpha); \
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
+ } \
+ } \
+}
+
void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
int w, int h,
int const_alpha)
{
const quint32 *src = (const quint32 *) srcPixels;
- quint32 *dst = (uint *) destPixels;
+ quint32 *dst = (quint32 *) destPixels;
if (const_alpha == 256) {
const __m128i alphaMask = _mm_set1_epi32(0xff000000);
const __m128i nullVector = _mm_set1_epi32(0);
@@ -140,41 +227,7 @@ void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
const __m128i one = _mm_set1_epi16(0xff);
const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
for (int y = 0; y < h; ++y) {
- int x = 0;
- for (; x < w-3; x += 4) {
- const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
- const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask);
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) {
- // all opaque
- _mm_storeu_si128((__m128i *)&dst[x], srcVector);
- } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) {
- // not fully transparent
- // result = s + d * (1-alpha)
-
- // extract the alpha channel on 2 x 16 bits
- // so we have room for the multiplication
- // each 32 bits will be in the form 0x00AA00AA
- // with A being the 1 - alpha
- __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
- alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
- alphaChannel = _mm_sub_epi16(one, alphaChannel);
-
- const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
- __m128i destMultipliedByOneMinusAlpha;
- BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half);
-
- // result = s + d * (1-alpha)
- const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha);
- _mm_storeu_si128((__m128i *)&dst[x], result);
- }
- }
- for (; x<w; ++x) {
- uint s = src[x];
- if (s >= 0xff000000)
- dst[x] = s;
- else if (s != 0)
- dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
- }
+ BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, w, nullVector, half, one, colorMask, alphaMask);
dst = (quint32 *)(((uchar *) dst) + dbpl);
src = (const quint32 *)(((const uchar *) src) + sbpl);
}
@@ -189,31 +242,7 @@ void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
for (int y = 0; y < h; ++y) {
- int x = 0;
- for (; x < w-3; x += 4) {
- __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) {
- BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half);
-
- __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
- alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
- alphaChannel = _mm_sub_epi16(one, alphaChannel);
-
- const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
- __m128i destMultipliedByOneMinusAlpha;
- BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half);
-
- const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha);
- _mm_storeu_si128((__m128i *)&dst[x], result);
- }
- }
- for (; x<w; ++x) {
- quint32 s = src[x];
- if (s != 0) {
- s = BYTE_MUL(s, const_alpha);
- dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
- }
- }
+ BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, w, nullVector, half, one, colorMask, constAlphaVector)
dst = (quint32 *)(((uchar *) dst) + dbpl);
src = (const quint32 *)(((const uchar *) src) + sbpl);
}
@@ -232,7 +261,7 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
int const_alpha)
{
const quint32 *src = (const quint32 *) srcPixels;
- quint32 *dst = (uint *) destPixels;
+ quint32 *dst = (quint32 *) destPixels;
if (const_alpha != 256) {
if (const_alpha != 0) {
const __m128i nullVector = _mm_set1_epi32(0);
@@ -268,6 +297,27 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
}
}
+void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha)
+{
+ Q_ASSERT(const_alpha >= 0);
+ Q_ASSERT(const_alpha < 256);
+
+ const quint32 *src = (const quint32 *) srcPixels;
+ quint32 *dst = (quint32 *) destPixels;
+
+ const __m128i nullVector = _mm_set1_epi32(0);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i one = _mm_set1_epi16(0xff);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ if (const_alpha == 255) {
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, length, nullVector, half, one, colorMask, alphaMask);
+ } else {
+ const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
+ BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, length, nullVector, half, one, colorMask, constAlphaVector);
+ }
+}
+
void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
{
if (count < 7) {
@@ -312,6 +362,34 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
}
}
+void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha)
+{
+ if ((const_alpha & qAlpha(color)) == 255) {
+ qt_memfill32_sse2(destPixels, color, length);
+ } else {
+ if (const_alpha != 255)
+ color = BYTE_MUL(color, const_alpha);
+
+ const quint32 minusAlphaOfColor = qAlpha(~color);
+ int x = 0;
+
+ quint32 *dst = (quint32 *) destPixels;
+ const __m128i colorVector = _mm_set1_epi32(color);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i minusAlphaOfColorVector = _mm_set1_epi16(minusAlphaOfColor);
+
+ for (; x < length-3; x += 4) {
+ __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
+ BYTE_MUL_SSE2(dstVector, dstVector, minusAlphaOfColorVector, colorMask, half);
+ dstVector = _mm_add_epi8(colorVector, dstVector);
+ _mm_storeu_si128((__m128i *)&dst[x], dstVector);
+ }
+ for (;x < length; ++x)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
+ }
+}
+
void qt_memfill16_sse2(quint16 *dest, quint16 value, int count)
{
if (count < 3) {
diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp
index 2ea3d33..69ce47e 100644
--- a/src/gui/painting/qgraphicssystem.cpp
+++ b/src/gui/painting/qgraphicssystem.cpp
@@ -79,5 +79,9 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ
return 0;
}
+QPixmapData *QGraphicsSystem::createPixmapData(QPixmapData *origin)
+{
+ return createPixmapData(origin->pixelType());
+}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qgraphicssystem_p.h b/src/gui/painting/qgraphicssystem_p.h
index ddca788..1211505 100644
--- a/src/gui/painting/qgraphicssystem_p.h
+++ b/src/gui/painting/qgraphicssystem_p.h
@@ -64,6 +64,7 @@ class Q_GUI_EXPORT QGraphicsSystem
{
public:
virtual QPixmapData *createPixmapData(QPixmapData::PixelType type) const = 0;
+ virtual QPixmapData *createPixmapData(QPixmapData *origin);
virtual QWindowSurface *createWindowSurface(QWidget *widget) const = 0;
virtual ~QGraphicsSystem() = 0;
diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp
index 32a8578..1c3ae10 100644
--- a/src/gui/painting/qgraphicssystem_runtime.cpp
+++ b/src/gui/painting/qgraphicssystem_runtime.cpp
@@ -416,7 +416,7 @@ void QRuntimeGraphicsSystem::setGraphicsSystem(const QString &name)
for (int i = 0; i < m_pixmapDatas.size(); ++i) {
QRuntimePixmapData *proxy = m_pixmapDatas.at(i);
- QPixmapData *newData = m_graphicsSystem->createPixmapData(proxy->m_data->pixelType());
+ QPixmapData *newData = m_graphicsSystem->createPixmapData(proxy->m_data);
// ### TODO Optimize. Openvg and s60raster graphics systems could switch internal ARGB32_PRE QImage buffers.
newData->fromImage(proxy->m_data->toImage(), Qt::AutoColor | Qt::OrderedAlphaDither);
delete proxy->m_data;
diff --git a/src/gui/painting/qgraphicssystem_runtime_p.h b/src/gui/painting/qgraphicssystem_runtime_p.h
index 101a8e7..7aab89c 100644
--- a/src/gui/painting/qgraphicssystem_runtime_p.h
+++ b/src/gui/painting/qgraphicssystem_runtime_p.h
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
class QRuntimeGraphicsSystem;
-class QRuntimePixmapData : public QPixmapData {
+class Q_GUI_EXPORT QRuntimePixmapData : public QPixmapData {
public:
QRuntimePixmapData(const QRuntimeGraphicsSystem *gs, PixelType type);
~QRuntimePixmapData();
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index c37aa51..6888bb0 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -594,4 +594,55 @@ void Q_GUI_EXPORT qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHei
qt_memrotate90_template(src, srcWidth, srcHeight, srcStride, reinterpret_cast<qrgb_gl_rgba *>(dest), dstStride);
}
+void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate180_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate270_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate90_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+void qt_memrotate180_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] =
+// 90, 180, 270
+{
+ { 0, 0, 0 }, // Format_Invalid,
+ { 0, 0, 0 }, // Format_Mono,
+ { 0, 0, 0 }, // Format_MonoLSB,
+ { 0, 0, 0 }, // Format_Indexed8,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB32,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32_Premultiplied,
+ { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // Format_RGB16,
+ { 0, 0, 0 }, // Format_ARGB8565_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB666,
+ { 0, 0, 0 }, // Format_ARGB6666_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB555,
+ { 0, 0, 0 }, // Format_ARGB8555_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB888,
+ { 0, 0, 0 }, // Format_RGB444,
+ { 0, 0, 0 } // Format_ARGB4444_Premultiplied,
+};
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index a212718..09a87aa 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -2419,7 +2419,9 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons
drawImage(r, image, sr);
}
} else {
- const QImage image = pixmap.toImage();
+ QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
+ const QImage image = pd->toImage(clippedSource);
+ QRectF translatedSource = sr.translated(-clippedSource.topLeft());
if (image.depth() == 1) {
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
@@ -2430,10 +2432,10 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons
drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
return;
} else {
- drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
+ drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
}
} else {
- drawImage(r, image, sr);
+ drawImage(r, image, translatedSource);
}
}
}
@@ -2551,23 +2553,6 @@ namespace {
return NoRotation;
}
- template <typename T> void memRotate(RotationType type, const T *srcBase, int w, int h, int sbpl, T *dstBase, int dbpl)
- {
- switch (type) {
- case Rotation90:
- qt_memrotate90(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case Rotation180:
- qt_memrotate180(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case Rotation270:
- qt_memrotate270(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case NoRotation:
- break;
- }
- }
-
inline bool isPixelAligned(const QRectF &rect) {
return QRectF(rect.toRect()) == rect;
}
@@ -2648,7 +2633,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
{
RotationType rotationType = qRotationType(s->matrix);
- if (rotationType != NoRotation && img.rect().contains(sr.toAlignedRect())) {
+ if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
QRectF transformedTargetRect = s->matrix.mapRect(r);
if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
@@ -2676,10 +2661,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
uint cw = clippedSourceRect.width();
uint ch = clippedSourceRect.height();
- if (d->rasterBuffer->format == QImage::Format_RGB16)
- memRotate(rotationType, (quint16 *)srcBase, cw, ch, sbpl, (quint16 *)dstBase, dbpl);
- else
- memRotate(rotationType, (quint32 *)srcBase, cw, ch, sbpl, (quint32 *)dstBase, dbpl);
+ qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
return;
}
@@ -2688,7 +2670,11 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
- if (s->flags.fast_images) {
+ QRectF targetBounds = s->matrix.mapRect(r);
+ bool exceedsPrecision = targetBounds.width() > 0xffff
+ || targetBounds.height() > 0xffff;
+
+ if (s->flags.fast_images && !exceedsPrecision) {
if (s->matrix.type() > QTransform::TxScale) {
SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
if (func && (!clip || clip->hasRectClip)) {
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 71bc990..2ea6673 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -5958,7 +5958,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif
Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
}
- QTextItemInt gf(glyphs, &d->state->font, fontEngine);
+ QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine);
drawTextItem(p, gf);
return;
}
diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp
index 78553c9..a17b7c1 100644
--- a/src/gui/painting/qpathclipper.cpp
+++ b/src/gui/painting/qpathclipper.cpp
@@ -86,9 +86,11 @@ static qreal dot(const QPointF &a, const QPointF &b)
return a.x() * b.x() + a.y() * b.y();
}
-static QPointF normalize(const QPointF &p)
+static void normalize(double &x, double &y)
{
- return p / qSqrt(p.x() * p.x() + p.y() * p.y());
+ double reciprocal = 1 / qSqrt(x * x + y * y);
+ x *= reciprocal;
+ y *= reciprocal;
}
struct QIntersection
@@ -1017,8 +1019,8 @@ qreal QWingedEdge::delta(int vertex, int a, int b) const
const QPathEdge *ap = edge(a);
const QPathEdge *bp = edge(b);
- qreal a_angle = ap->angle;
- qreal b_angle = bp->angle;
+ double a_angle = ap->angle;
+ double b_angle = bp->angle;
if (vertex == ap->second)
a_angle = ap->invAngle;
@@ -1026,7 +1028,7 @@ qreal QWingedEdge::delta(int vertex, int a, int b) const
if (vertex == bp->second)
b_angle = bp->invAngle;
- qreal result = b_angle - a_angle;
+ double result = b_angle - a_angle;
if (result >= 128.)
return result - 128.;
@@ -1036,26 +1038,6 @@ qreal QWingedEdge::delta(int vertex, int a, int b) const
return result;
}
-static inline QPointF tangentAt(const QWingedEdge &list, int vi, int ei)
-{
- const QPathEdge *ep = list.edge(ei);
- Q_ASSERT(ep);
-
- qreal sign;
-
- if (ep->first == vi) {
- sign = 1;
- } else {
- sign = -1;
- }
-
- const QPointF a = *list.vertex(ep->first);
- const QPointF b = *list.vertex(ep->second);
- QPointF normal = b - a;
-
- return normalize(sign * normal);
-}
-
static inline QPointF midPoint(const QWingedEdge &list, int ei)
{
const QPathEdge *ep = list.edge(ei);
@@ -1191,7 +1173,7 @@ static int commonEdge(const QWingedEdge &list, int a, int b)
return -1;
}
-static qreal computeAngle(const QPointF &v)
+static double computeAngle(const QPointF &v)
{
#if 1
if (v.x() == 0) {
@@ -1200,15 +1182,17 @@ static qreal computeAngle(const QPointF &v)
return v.x() <= 0 ? 32. : 96.;
}
- QPointF nv = normalize(v);
- if (nv.y() < 0) {
- if (nv.x() < 0) { // 0 - 32
- return -32. * nv.x();
+ double vx = v.x();
+ double vy = v.y();
+ normalize(vx, vy);
+ if (vy < 0) {
+ if (vx < 0) { // 0 - 32
+ return -32. * vx;
} else { // 96 - 128
- return 128. - 32. * nv.x();
+ return 128. - 32. * vx;
}
} else { // 32 - 96
- return 64. + 32 * nv.x();
+ return 64. + 32. * vx;
}
#else
// doesn't seem to be robust enough
diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h
index fab618d..bdad4e1 100644
--- a/src/gui/painting/qpathclipper_p.h
+++ b/src/gui/painting/qpathclipper_p.h
@@ -148,8 +148,8 @@ public:
int first;
int second;
- qreal angle;
- qreal invAngle;
+ double angle;
+ double invAngle;
int next(Traversal traversal, Direction direction) const;
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 60195a8..439f2a4 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2668,9 +2668,9 @@ QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFo
flags |= QTextItem::StrikeOut;
}
-QTextItemInt::QTextItemInt(const QGlyphLayout &g, QFont *font, QFontEngine *fe)
+QTextItemInt::QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars_, int numChars, QFontEngine *fe)
: flags(0), justified(false), underlineStyle(QTextCharFormat::NoUnderline),
- num_chars(0), chars(0), logClusters(0), f(font), glyphs(g), fontEngine(fe)
+ num_chars(numChars), chars(chars_), logClusters(0), f(font), glyphs(g), fontEngine(fe)
{
}
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 908a0ec..e623fa5 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -311,7 +311,7 @@ public:
logClusters(0), f(0), fontEngine(0)
{}
QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
- QTextItemInt(const QGlyphLayout &g, QFont *font, QFontEngine *fe);
+ QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe);
/// copy the structure items, adjusting the glyphs arrays to the right subarrays.
/// the width of the returned QTextItemInt is not adjusted, for speed reasons
diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp
index aa4ffce..e8e80b7 100644
--- a/src/gui/widgets/qmenubar.cpp
+++ b/src/gui/widgets/qmenubar.cpp
@@ -768,7 +768,7 @@ QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) c
const int start = (_start == -1 && increment == -1) ? actions.count() : _start;
const int end = increment == -1 ? 0 : actions.count() - 1;
- for (int i = start; start != end;) {
+ for (int i = start; i != end;) {
i += increment;
QAction *current = actions.at(i);
if (!actionRects.at(i).isNull() && (allowActiveAndDisabled || current->isEnabled()))