diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-26 14:49:31 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-26 14:49:31 (GMT) |
commit | 25620750ff88251717b38d2ff4bc8818e89c9bb4 (patch) | |
tree | 297787e4963cc41deb287124721213ffaa61e9ff /src/gui | |
parent | 4fb6cae4dd0c6a90008780df606abb8a9e73cb2c (diff) | |
parent | ed8b490ff07afbca5f23aa19d995c017e2823114 (diff) | |
download | Qt-25620750ff88251717b38d2ff4bc8818e89c9bb4.zip Qt-25620750ff88251717b38d2ff4bc8818e89c9bb4.tar.gz Qt-25620750ff88251717b38d2ff4bc8818e89c9bb4.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2: (29 commits)
cetest: remove source file duplicates from cetest.pro
Remove EGLImage create/destroy resolving from VG pixmap data
Avoid having to create temporary QPixmaps when binding to texture
Implement Texture-From-Pixmap using EGLImage extensions on X11/EGL
Stabilize tst_QTreeView::taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint
QMetaObject::normalizeType: Fix parsing of type which contains "const" in names
QMetaObject::normalizeType: fix uses of const and template.
Synchronize rich text and plain text code paths in QStaticText
Paintbuffer single frame profiling.
Optimized ARGB32PM on RGB16 blending with opacity using NEON.
Optimized SourceOver and 16 bit dest fetches, dest stores using NEON.
Optimized scaled/transformed image blending for ARGB32PM and RGB16 on RGB16.
Included ARM NEON optimizations from pixman in Qt.
Safeguard the colortable access when converting corrupted indexed8
Fix QItemDelegate::textRectangle
Fix bad merge
Fix wrong arguments order in a warning in QObject::moveToThread
Fix warnings and build on mingw
Fixes a deadlock with streaming in Phonon.
cetest build fix
...
Diffstat (limited to 'src/gui')
25 files changed, 1905 insertions, 1003 deletions
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index b870523..507fab3 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -528,6 +528,9 @@ QEglProperties QEglContext::configProperties() const return QEglProperties(config()); } +_eglCreateImageKHR eglCreateImageKHR = 0; +_eglDestroyImageKHR eglDestroyImageKHR = 0; + EGLDisplay QEgl::display() { static EGLDisplay dpy = EGL_NO_DISPLAY; @@ -549,6 +552,12 @@ EGLDisplay QEgl::display() qWarning() << "QEgl::display(): Cannot initialize EGL display:" << QEgl::errorString(); return EGL_NO_DISPLAY; } + + // Resolve the egl extension function pointers: + if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_base")) { + eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); + eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); + } } return dpy; diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index 7dad9fe..b570329 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -100,13 +100,34 @@ typedef NativeDisplayType EGLNativeDisplayType; QT_END_INCLUDE_NAMESPACE #include <QtGui/qpaintdevice.h> - #include <QFlags> QT_BEGIN_NAMESPACE #define QEGL_NO_CONFIG ((EGLConfig)-1) +#ifndef EGLAPIENTRY +#define EGLAPIENTRY +#endif + +#if !defined(EGL_KHR_image) || !defined(EGL_KHR_image_base) + +typedef void *EGLImageKHR; +#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +typedef EGLImageKHR (EGLAPIENTRY *_eglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, EGLint*); +typedef EGLBoolean (EGLAPIENTRY *_eglDestroyImageKHR)(EGLDisplay, EGLImageKHR); + +// Defined in qegl.cpp: +extern Q_GUI_EXPORT _eglCreateImageKHR eglCreateImageKHR; +extern Q_GUI_EXPORT _eglDestroyImageKHR eglDestroyImageKHR; + +#endif // !defined(EGL_KHR_image) || !defined(EGL_KHR_image_base) + +#if !defined(EGL_KHR_image) || !defined(EGL_KHR_image_pixmap) +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 +#endif class QEglProperties; @@ -132,7 +153,6 @@ namespace QEgl { }; Q_DECLARE_FLAGS(ConfigOptions, ConfigOption); - // Most of the time we use the same config for things like widgets & pixmaps, so rather than // go through the eglChooseConfig loop every time, we use defaultConfig, which will return // the config for a particular device/api/option combo. This function assumes that once a diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 948ff28..66b262c 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -381,7 +381,9 @@ \value ItemSendsGeometryChanges The item enables itemChange() notifications for ItemPositionChange, ItemPositionHasChanged, - ItemMatrixChange, ItemTransformChange, and ItemTransformHasChanged. For + ItemMatrixChange, ItemTransformChange, ItemTransformHasChanged, + ItemRotationChange, ItemRotationHasChanged, ItemScaleChange, ItemScaleHasChanged, + ItemTransformOriginPointChange, and ItemTransformOriginPointHasChanged. For performance reasons, these notifications are disabled by default. You must enable this flag to receive notifications for position and transform changes. This flag was introduced in Qt 4.6. @@ -475,6 +477,52 @@ (same as transform()), and QGraphicsItem ignores the return value for this notification (i.e., a read-only notification). + \value ItemRotationChange The item's rotation property changes. This + notification is sent if the ItemSendsGeometryChanges flag is enabled, and + when the item's rotation property changes (i.e., as a result of calling + setRotation()). The value argument is the new rotation (i.e., a double); + to get the old rotation, call rotation(). Do not call setRotation() in + itemChange() as this notification is delivered; instead, you can return + the new rotation from itemChange(). + + \value ItemRotationHasChanged The item's rotation property has changed. + This notification is sent if the ItemSendsGeometryChanges flag is enabled, + and after the item's rotation property has changed. The value argument is + the new rotation (i.e., a double), and QGraphicsItem ignores the return + value for this notification (i.e., a read-only notification). Do not call + setRotation() in itemChange() as this notification is delivered. + + \value ItemScaleChange The item's scale property changes. This notification + is sent if the ItemSendsGeometryChanges flag is enabled, and when the item's + scale property changes (i.e., as a result of calling setScale()). The value + argument is the new scale (i.e., a double); to get the old scale, call + scale(). Do not call setScale() in itemChange() as this notification is + delivered; instead, you can return the new scale from itemChange(). + + \value ItemScaleHasChanged The item's scale property has changed. This + notification is sent if the ItemSendsGeometryChanges flag is enabled, and + after the item's scale property has changed. The value argument is the new + scale (i.e., a double), and QGraphicsItem ignores the return value for this + notification (i.e., a read-only notification). Do not call setScale() in + itemChange() as this notification is delivered. + + \value ItemTransformOriginPointChange The item's transform origin point + property changes. This notification is sent if the ItemSendsGeometryChanges + flag is enabled, and when the item's transform origin point property changes + (i.e., as a result of calling setTransformOriginPoint()). The value argument + is the new origin point (i.e., a QPointF); to get the old origin point, call + transformOriginPoint(). Do not call setTransformOriginPoint() in itemChange() + as this notification is delivered; instead, you can return the new transform + origin point from itemChange(). + + \value ItemTransformOriginPointHasChanged The item's transform origin point + property has changed. This notification is sent if the ItemSendsGeometryChanges + flag is enabled, and after the item's transform origin point property has + changed. The value argument is the new origin point (i.e., a QPointF), and + QGraphicsItem ignores the return value for this notification (i.e., a read-only + notification). Do not call setTransformOriginPoint() in itemChange() as this + notification is delivered. + \value ItemSelectedChange The item's selected state changes. If the item is presently selected, it will become unselected, and vice verca. The value argument is the new selected state (i.e., true or false). Do not call @@ -3722,12 +3770,28 @@ qreal QGraphicsItem::rotation() const void QGraphicsItem::setRotation(qreal angle) { prepareGeometryChange(); + qreal newRotation = angle; + + if (d_ptr->flags & ItemSendsGeometryChanges) { + // Notify the item that the rotation is changing. + const QVariant newRotationVariant(itemChange(ItemRotationChange, angle)); + newRotation = newRotationVariant.toReal(); + } + if (!d_ptr->transformData) d_ptr->transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->transformData->rotation = angle; + + if (d_ptr->transformData->rotation == newRotation) + return; + + d_ptr->transformData->rotation = newRotation; d_ptr->transformData->onlyTransform = false; d_ptr->dirtySceneTransform = 1; + // Send post-notification. + if (d_ptr->flags & ItemSendsGeometryChanges) + itemChange(ItemRotationHasChanged, newRotation); + if (d_ptr->isObject) emit static_cast<QGraphicsObject *>(this)->rotationChanged(); } @@ -3770,12 +3834,28 @@ qreal QGraphicsItem::scale() const void QGraphicsItem::setScale(qreal factor) { prepareGeometryChange(); + qreal newScale = factor; + + if (d_ptr->flags & ItemSendsGeometryChanges) { + // Notify the item that the scale is changing. + const QVariant newScaleVariant(itemChange(ItemScaleChange, factor)); + newScale = newScaleVariant.toReal(); + } + if (!d_ptr->transformData) d_ptr->transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->transformData->scale = factor; + + if (d_ptr->transformData->scale == newScale) + return; + + d_ptr->transformData->scale = newScale; d_ptr->transformData->onlyTransform = false; d_ptr->dirtySceneTransform = 1; + // Send post-notification. + if (d_ptr->flags & ItemSendsGeometryChanges) + itemChange(ItemScaleHasChanged, newScale); + if (d_ptr->isObject) emit static_cast<QGraphicsObject *>(this)->scaleChanged(); } @@ -3877,12 +3957,31 @@ QPointF QGraphicsItem::transformOriginPoint() const void QGraphicsItem::setTransformOriginPoint(const QPointF &origin) { prepareGeometryChange(); + QPointF newOrigin = origin; + + if (d_ptr->flags & ItemSendsGeometryChanges) { + // Notify the item that the origin point is changing. + const QVariant newOriginVariant(itemChange(ItemTransformOriginPointChange, + qVariantFromValue<QPointF>(origin))); + newOrigin = newOriginVariant.toPointF(); + } + if (!d_ptr->transformData) d_ptr->transformData = new QGraphicsItemPrivate::TransformData; - d_ptr->transformData->xOrigin = origin.x(); - d_ptr->transformData->yOrigin = origin.y(); + + if (d_ptr->transformData->xOrigin == newOrigin.x() + && d_ptr->transformData->yOrigin == newOrigin.y()) { + return; + } + + d_ptr->transformData->xOrigin = newOrigin.x(); + d_ptr->transformData->yOrigin = newOrigin.y(); d_ptr->transformData->onlyTransform = false; d_ptr->dirtySceneTransform = 1; + + // Send post-notification. + if (d_ptr->flags & ItemSendsGeometryChanges) + itemChange(ItemTransformOriginPointHasChanged, qVariantFromValue<QPointF>(newOrigin)); } /*! @@ -11072,6 +11171,24 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change) case QGraphicsItem::ItemScenePositionHasChanged: str = "ItemScenePositionHasChanged"; break; + case QGraphicsItem::ItemRotationChange: + str = "ItemRotationChange"; + break; + case QGraphicsItem::ItemRotationHasChanged: + str = "ItemRotationHasChanged"; + break; + case QGraphicsItem::ItemScaleChange: + str = "ItemScaleChange"; + break; + case QGraphicsItem::ItemScaleHasChanged: + str = "ItemScaleHasChanged"; + break; + case QGraphicsItem::ItemTransformOriginPointChange: + str = "ItemTransformOriginPointChange"; + break; + case QGraphicsItem::ItemTransformOriginPointHasChanged: + str = "ItemTransformOriginPointHasChanged"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 56f94a2..117113f 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -139,7 +139,13 @@ public: ItemZValueHasChanged, ItemOpacityChange, ItemOpacityHasChanged, - ItemScenePositionHasChanged + ItemScenePositionHasChanged, + ItemRotationChange, + ItemRotationHasChanged, + ItemScaleChange, + ItemScaleHasChanged, + ItemTransformOriginPointChange, + ItemTransformOriginPointHasChanged }; enum CacheMode { diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 94307de..233c58d 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -2988,19 +2988,19 @@ static void convert_Indexed8_to_X32(QImageData *dest, const QImageData *src, Qt: colorTable.resize(256); for (int i=0; i<256; ++i) colorTable[i] = qRgb(i, i, i); - } int w = src->width; const uchar *src_data = src->data; uchar *dest_data = dest->data; + int tableSize = colorTable.size() - 1; for (int y = 0; y < src->height; y++) { uint *p = (uint *)dest_data; const uchar *b = src_data; uint *end = p + w; while (p < end) - *p++ = colorTable.at(*b++); + *p++ = colorTable.at(qMin<int>(tableSize, *b++)); src_data += src->bytes_per_line; dest_data += dest->bytes_per_line; diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index 3220a67..45b3ed0 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -651,7 +651,12 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords) s >> dbl; QFont fnt(font, painter->device()); - qreal scale = painter->device()->logicalDpiY() / (dbl*qt_defaultDpiY()); + // Fonts that specify a pixel size should not be scaled - QPicture already + // have a matrix set to compensate for the DPI differences between the + // default Qt DPI and the actual target device DPI, and we have to take that + // into consideration in the case where the font has a pixel size set. + + qreal scale = fnt.pointSize() == -1 ? 1 : painter->device()->logicalDpiY() / (dbl*qt_defaultDpiY()); painter->save(); painter->scale(1/scale, 1/scale); @@ -660,7 +665,7 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords) int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight; - QSizeF size(scale, scale); + QSizeF size(1, 1); if (justificationWidth > 0) { size.setWidth(justificationWidth*scale); flags |= Qt::TextJustificationForced; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 0b1c18d..b183d0d 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -182,6 +182,7 @@ void QRasterPixmapData::fromImage(const QImage &sourceImage, QImage::Format opaqueFormat = QNativeImage::systemFormat(); QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; +#ifndef QT_HAVE_NEON switch (opaqueFormat) { case QImage::Format_RGB16: alphaFormat = QImage::Format_ARGB8565_Premultiplied; @@ -189,6 +190,7 @@ void QRasterPixmapData::fromImage(const QImage &sourceImage, default: // We don't care about the others... break; } +#endif if (!sourceImage.hasAlphaChannel() || ((flags & Qt::NoOpaqueDetection) == 0 @@ -238,6 +240,7 @@ void QRasterPixmapData::fill(const QColor &color) if (alpha != 255) { if (!image.hasAlphaChannel()) { QImage::Format toFormat; +#ifndef QT_HAVE_NEON if (image.format() == QImage::Format_RGB16) toFormat = QImage::Format_ARGB8565_Premultiplied; else if (image.format() == QImage::Format_RGB666) @@ -247,6 +250,7 @@ void QRasterPixmapData::fill(const QColor &color) else if (image.format() == QImage::Format_RGB444) toFormat = QImage::Format_ARGB4444_Premultiplied; else +#endif toFormat = QImage::Format_ARGB32_Premultiplied; image = QImage(image.width(), image.height(), toFormat); } diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index cba213b..d5f6fd2 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -69,6 +69,7 @@ #include <qdebug.h> #include <qlocale.h> #include <qdialog.h> +#include <qmath.h> #include <limits.h> @@ -1148,7 +1149,8 @@ QRect QItemDelegate::textRectangle(QPainter * /*painter*/, const QRect &rect, d->textLayout.setTextOption(d->textOption); d->textLayout.setFont(font); d->textLayout.setText(QItemDelegatePrivate::replaceNewLine(text)); - const QSize size = d->doTextLayout(rect.width()).toSize(); + QSizeF fpSize = d->doTextLayout(rect.width()); + const QSize size = QSize(qCeil(fpSize.width()), qCeil(fpSize.height())); // ###: textRectangle should take style option as argument const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; return QRect(0, 0, size.width() + 2 * textMargin, size.height()); diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index a6cc9c7..ed8ee76 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -91,6 +91,8 @@ SOURCES += \ HEADERS += \ painting/qpaintengine_raster_p.h \ + painting/qdrawhelper_p.h \ + painting/qblendfunctions_p.h \ painting/qrasterdefs_p.h \ painting/qgrayraster_p.h @@ -379,11 +381,23 @@ symbian { QMAKE_CXXFLAGS.ARMCC *= -O3 } -neon { +neon:*-g++* { DEFINES += QT_HAVE_NEON HEADERS += painting/qdrawhelper_neon_p.h SOURCES += painting/qdrawhelper_neon.cpp QMAKE_CXXFLAGS *= -mfpu=neon + + DRAWHELPER_NEON_ASM_FILES = ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S + + neon_compiler.commands = $$QMAKE_CXX -c + neon_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} + neon_compiler.dependency_type = TYPE_C + neon_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} + neon_compiler.input = DRAWHELPER_NEON_ASM_FILES + neon_compiler.variable_out = OBJECTS + neon_compiler.name = compiling[neon] ${QMAKE_FILE_IN} + silent:neon_compiler.commands = @echo compiling[neon] ${QMAKE_FILE_IN} && $$neon_compiler.commands + QMAKE_EXTRA_COMPILERS += neon_compiler } contains(QT_CONFIG, zlib) { diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index dc33896..24908ce 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include <qmath.h> -#include "qdrawhelper_p.h" +#include "qblendfunctions_p.h" QT_BEGIN_NAMESPACE @@ -88,6 +88,8 @@ static inline quint16 convert_argb32_to_rgb16(quint32 spix) struct Blend_RGB16_on_RGB16_NoAlpha { inline void write(quint16 *dst, quint16 src) { *dst = src; } + + inline void flush(void *) {} }; struct Blend_RGB16_on_RGB16_ConstAlpha { @@ -100,6 +102,8 @@ struct Blend_RGB16_on_RGB16_ConstAlpha { *dst = BYTE_MUL_RGB16(src, m_alpha) + BYTE_MUL_RGB16(*dst, m_ialpha); } + inline void flush(void *) {} + quint32 m_alpha; quint32 m_ialpha; }; @@ -114,6 +118,8 @@ struct Blend_ARGB24_on_RGB16_SourceAlpha { *dst = s; } } + + inline void flush(void *) {} }; struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha { @@ -132,6 +138,8 @@ struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha { } } + inline void flush(void *) {} + quint32 m_alpha; }; @@ -145,6 +153,8 @@ struct Blend_ARGB32_on_RGB16_SourceAlpha { *dst = s; } } + + inline void flush(void *) {} }; struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha { @@ -163,99 +173,11 @@ struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha { } } + inline void flush(void *) {} + quint32 m_alpha; }; -template <typename SRC, typename T> -void qt_scale_image_16bit(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - const QRectF &targetRect, - const QRectF &srcRect, - const QRect &clip, - T blender) -{ - qreal sx = targetRect.width() / (qreal) srcRect.width(); - qreal sy = targetRect.height() / (qreal) srcRect.height(); - - int ix = 0x00010000 / sx; - int iy = 0x00010000 / sy; - -// qDebug() << "scale:" << endl -// << " - target" << targetRect << endl -// << " - source" << srcRect << endl -// << " - clip" << clip << endl -// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; - - int cx1 = clip.x(); - int cx2 = clip.x() + clip.width(); - int cy1 = clip.top(); - int cy2 = clip.y() + clip.height(); - - int tx1 = qRound(targetRect.left()); - int tx2 = qRound(targetRect.right()); - int ty1 = qRound(targetRect.top()); - int ty2 = qRound(targetRect.bottom()); - - if (tx2 < tx1) - qSwap(tx2, tx1); - - if (ty2 < ty1) - qSwap(ty2, ty1); - - if (tx1 < cx1) - tx1 = cx1; - - if (tx2 >= cx2) - tx2 = cx2; - - if (tx1 >= tx2) - return; - - if (ty1 < cy1) - ty1 = cy1; - - if (ty2 >= cy2) - ty2 = cy2; - - if (ty1 >= ty2) - return; - - int h = ty2 - ty1; - int w = tx2 - tx1; - - - quint32 basex; - quint32 srcy; - - if (sx < 0) { - int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; - basex = quint32(srcRect.right() * 65536) + dstx; - } else { - int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; - basex = quint32(srcRect.left() * 65536) + dstx; - } - if (sy < 0) { - int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; - srcy = quint32(srcRect.bottom() * 65536) + dsty; - } else { - int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; - srcy = quint32(srcRect.top() * 65536) + dsty; - } - - quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1; - - while (h--) { - const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl); - int srcx = basex; - for (int x=0; x<w; ++x) { - blender.write(&dst[x], src[srcx >> 16]); - srcx += ix; - } - dst = (quint16 *)(((uchar *) dst) + dbpl); - srcy += iy; - } -} - void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, const QRectF &targetRect, @@ -447,10 +369,10 @@ static void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl, -static void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { quint16 *dst = (quint16 *) destPixels; const quint32 *src = (const quint32 *) srcPixels; @@ -643,6 +565,8 @@ void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, struct Blend_RGB32_on_RGB32_NoAlpha { inline void write(quint32 *dst, quint32 src) { *dst = src; } + + inline void flush(void *) {} }; struct Blend_RGB32_on_RGB32_ConstAlpha { @@ -655,6 +579,8 @@ struct Blend_RGB32_on_RGB32_ConstAlpha { *dst = BYTE_MUL(src, m_alpha) + BYTE_MUL(*dst, m_ialpha); } + inline void flush(void *) {} + quint32 m_alpha; quint32 m_ialpha; }; @@ -663,6 +589,8 @@ struct Blend_ARGB32_on_ARGB32_SourceAlpha { inline void write(quint32 *dst, quint32 src) { *dst = src + BYTE_MUL(*dst, qAlpha(~src)); } + + inline void flush(void *) {} }; struct Blend_ARGB32_on_ARGB32_SourceAndConstAlpha { @@ -676,98 +604,12 @@ struct Blend_ARGB32_on_ARGB32_SourceAndConstAlpha { *dst = src + BYTE_MUL(*dst, qAlpha(~src)); } + inline void flush(void *) {} + quint32 m_alpha; quint32 m_ialpha; }; -template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - const QRectF &targetRect, - const QRectF &srcRect, - const QRect &clip, - T blender) -{ - qreal sx = targetRect.width() / (qreal) srcRect.width(); - qreal sy = targetRect.height() / (qreal) srcRect.height(); - - int ix = 0x00010000 / sx; - int iy = 0x00010000 / sy; - -// qDebug() << "scale:" << endl -// << " - target" << targetRect << endl -// << " - source" << srcRect << endl -// << " - clip" << clip << endl -// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; - - int cx1 = clip.x(); - int cx2 = clip.x() + clip.width(); - int cy1 = clip.top(); - int cy2 = clip.y() + clip.height(); - - int tx1 = qRound(targetRect.left()); - int tx2 = qRound(targetRect.right()); - int ty1 = qRound(targetRect.top()); - int ty2 = qRound(targetRect.bottom()); - - if (tx2 < tx1) - qSwap(tx2, tx1); - - if (ty2 < ty1) - qSwap(ty2, ty1); - - if (tx1 < cx1) - tx1 = cx1; - - if (tx2 >= cx2) - tx2 = cx2; - - if (tx1 >= tx2) - return; - - if (ty1 < cy1) - ty1 = cy1; - - if (ty2 >= cy2) - ty2 = cy2; - - if (ty1 >= ty2) - return; - - int h = ty2 - ty1; - int w = tx2 - tx1; - - quint32 basex; - quint32 srcy; - - if (sx < 0) { - int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; - basex = quint32(srcRect.right() * 65536) + dstx; - } else { - int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; - basex = quint32(srcRect.left() * 65536) + dstx; - } - if (sy < 0) { - int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; - srcy = quint32(srcRect.bottom() * 65536) + dsty; - } else { - int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; - srcy = quint32(srcRect.top() * 65536) + dsty; - } - - quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1; - - while (h--) { - const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl); - int srcx = basex; - for (int x=0; x<w; ++x) { - blender.write(&dst[x], src[srcx >> 16]); - srcx += ix; - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - srcy += iy; - } -} - void qt_scale_image_rgb32_on_rgb32(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, const QRectF &targetRect, @@ -818,244 +660,6 @@ void qt_scale_image_argb32_on_argb32(uchar *destPixels, int dbpl, } } -struct QTransformImageVertex -{ - qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v) -}; - -template <class SrcT, class DestT, class Blender> -void qt_transform_image_rasterize(DestT *destPixels, int dbpl, - const SrcT *srcPixels, int sbpl, - const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft, - const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight, - const QRect &sourceRect, - const QRect &clip, - qreal topY, qreal bottomY, - int dudx, int dvdx, int dudy, int dvdy, int u0, int v0, - Blender blender) -{ - int fromY = qMax(qRound(topY), clip.top()); - int toY = qMin(qRound(bottomY), clip.top() + clip.height()); - if (fromY >= toY) - return; - - qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y); - qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y); - int dx_l = int(leftSlope * 0x10000); - int dx_r = int(rightSlope * 0x10000); - int x_l = int((topLeft.x + (0.5 + fromY - topLeft.y) * leftSlope + 0.5) * 0x10000); - int x_r = int((topRight.x + (0.5 + fromY - topRight.y) * rightSlope + 0.5) * 0x10000); - - int fromX, toX, x1, x2, u, v, i, ii; - DestT *line; - for (int y = fromY; y < toY; ++y) { - line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl); - - fromX = qMax(x_l >> 16, clip.left()); - toX = qMin(x_r >> 16, clip.left() + clip.width()); - if (fromX < toX) { - // Because of rounding, we can get source coordinates outside the source image. - // Clamp these coordinates to the source rect to avoid segmentation fault and - // garbage on the screen. - - // Find the first pixel on the current scan line where the source coordinates are within the source rect. - x1 = fromX; - u = x1 * dudx + y * dudy + u0; - v = x1 * dvdx + y * dvdy + v0; - for (; x1 < toX; ++x1) { - int uu = u >> 16; - int vv = v >> 16; - if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width() - && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) { - break; - } - u += dudx; - v += dvdx; - } - - // Find the last pixel on the current scan line where the source coordinates are within the source rect. - x2 = toX; - u = (x2 - 1) * dudx + y * dudy + u0; - v = (x2 - 1) * dvdx + y * dvdy + v0; - for (; x2 > x1; --x2) { - int uu = u >> 16; - int vv = v >> 16; - if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width() - && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) { - break; - } - u -= dudx; - v -= dvdx; - } - - // Set up values at the beginning of the scan line. - u = fromX * dudx + y * dudy + u0; - v = fromX * dvdx + y * dvdy + v0; - line += fromX; - - // Beginning of the scan line, with per-pixel checks. - i = x1 - fromX; - while (i) { - int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1); - int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1); - blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); - u += dudx; - v += dvdx; - ++line; - --i; - } - - // Middle of the scan line, without checks. - // Manual loop unrolling. - i = x2 - x1; - ii = i >> 3; - while (ii) { - blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; - line += 8; - --ii; - } - switch (i & 7) { - case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; - } - - // End of the scan line, with per-pixel checks. - i = toX - x2; - while (i) { - int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1); - int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1); - blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); - u += dudx; - v += dvdx; - ++line; - --i; - } - } - x_l += dx_l; - x_r += dx_r; - } -} - -template <class SrcT, class DestT, class Blender> -void qt_transform_image(DestT *destPixels, int dbpl, - const SrcT *srcPixels, int sbpl, - const QRectF &targetRect, - const QRectF &sourceRect, - const QRect &clip, - const QTransform &targetRectTransform, - Blender blender) -{ - enum Corner - { - TopLeft, - TopRight, - BottomRight, - BottomLeft - }; - - // map source rectangle to destination. - QTransformImageVertex v[4]; - v[TopLeft].u = v[BottomLeft].u = sourceRect.left(); - v[TopLeft].v = v[TopRight].v = sourceRect.top(); - v[TopRight].u = v[BottomRight].u = sourceRect.right(); - v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom(); - targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y); - targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y); - targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y); - targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y); - - // find topmost vertex. - int topmost = 0; - for (int i = 1; i < 4; ++i) { - if (v[i].y < v[topmost].y) - topmost = i; - } - // rearrange array such that topmost vertex is at index 0. - switch (topmost) { - case 1: - { - QTransformImageVertex t = v[0]; - for (int i = 0; i < 3; ++i) - v[i] = v[i+1]; - v[3] = t; - } - break; - case 2: - qSwap(v[0], v[2]); - qSwap(v[1], v[3]); - break; - case 3: - { - QTransformImageVertex t = v[3]; - for (int i = 3; i > 0; --i) - v[i] = v[i-1]; - v[0] = t; - } - break; - } - - // if necessary, swap vertex 1 and 3 such that 1 is to the left of 3. - qreal dx1 = v[1].x - v[0].x; - qreal dy1 = v[1].y - v[0].y; - qreal dx2 = v[3].x - v[0].x; - qreal dy2 = v[3].y - v[0].y; - if (dx1 * dy2 - dx2 * dy1 > 0) - qSwap(v[1], v[3]); - - QTransformImageVertex u = {v[1].x - v[0].x, v[1].y - v[0].y, v[1].u - v[0].u, v[1].v - v[0].v}; - QTransformImageVertex w = {v[2].x - v[0].x, v[2].y - v[0].y, v[2].u - v[0].u, v[2].v - v[0].v}; - - qreal det = u.x * w.y - u.y * w.x; - if (det == 0) - return; - - qreal invDet = 1.0 / det; - qreal m11, m12, m21, m22, mdx, mdy; - - m11 = (u.u * w.y - u.y * w.u) * invDet; - m12 = (u.x * w.u - u.u * w.x) * invDet; - m21 = (u.v * w.y - u.y * w.v) * invDet; - m22 = (u.x * w.v - u.v * w.x) * invDet; - mdx = v[0].u - m11 * v[0].x - m12 * v[0].y; - mdy = v[0].v - m21 * v[0].x - m22 * v[0].y; - - int dudx = int(m11 * 0x10000); - int dvdx = int(m21 * 0x10000); - int dudy = int(m12 * 0x10000); - int dvdy = int(m22 * 0x10000); - int u0 = qCeil((0.5 * m11 + 0.5 * m12 + mdx) * 0x10000) - 1; - int v0 = qCeil((0.5 * m21 + 0.5 * m22 + mdy) * 0x10000) - 1; - - int x1 = qFloor(sourceRect.left()); - int y1 = qFloor(sourceRect.top()); - int x2 = qCeil(sourceRect.right()); - int y2 = qCeil(sourceRect.bottom()); - QRect sourceRectI(x1, y1, x2 - x1, y2 - y1); - - // rasterize trapezoids. - if (v[1].y < v[3].y) { - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[0], v[3], sourceRectI, clip, v[1].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[3].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - } else { - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[3], v[2], sourceRectI, clip, v[3].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[1].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); - } -} - void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, const QRectF &targetRect, diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h new file mode 100644 index 0000000..ad754b0 --- /dev/null +++ b/src/gui/painting/qblendfunctions_p.h @@ -0,0 +1,497 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBLENDFUNCTIONS_P_H +#define QBLENDFUNCTIONS_P_H + +#include <qmath.h> +#include "qdrawhelper_p.h" + +QT_BEGIN_NAMESPACE + +// +// 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. +// + +template <typename SRC, typename T> +void qt_scale_image_16bit(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &srcRect, + const QRect &clip, + T blender) +{ + qreal sx = targetRect.width() / (qreal) srcRect.width(); + qreal sy = targetRect.height() / (qreal) srcRect.height(); + + int ix = 0x00010000 / sx; + int iy = 0x00010000 / sy; + +// qDebug() << "scale:" << endl +// << " - target" << targetRect << endl +// << " - source" << srcRect << endl +// << " - clip" << clip << endl +// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; + + int cx1 = clip.x(); + int cx2 = clip.x() + clip.width(); + int cy1 = clip.top(); + int cy2 = clip.y() + clip.height(); + + int tx1 = qRound(targetRect.left()); + int tx2 = qRound(targetRect.right()); + int ty1 = qRound(targetRect.top()); + int ty2 = qRound(targetRect.bottom()); + + if (tx2 < tx1) + qSwap(tx2, tx1); + + if (ty2 < ty1) + qSwap(ty2, ty1); + + if (tx1 < cx1) + tx1 = cx1; + + if (tx2 >= cx2) + tx2 = cx2; + + if (tx1 >= tx2) + return; + + if (ty1 < cy1) + ty1 = cy1; + + if (ty2 >= cy2) + ty2 = cy2; + + if (ty1 >= ty2) + return; + + int h = ty2 - ty1; + int w = tx2 - tx1; + + + quint32 basex; + quint32 srcy; + + if (sx < 0) { + int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; + basex = quint32(srcRect.right() * 65536) + dstx; + } else { + int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; + basex = quint32(srcRect.left() * 65536) + dstx; + } + if (sy < 0) { + int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; + srcy = quint32(srcRect.bottom() * 65536) + dsty; + } else { + int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; + srcy = quint32(srcRect.top() * 65536) + dsty; + } + + quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1; + + while (h--) { + const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl); + int srcx = basex; + int x = 0; + for (; x<w-7; x+=8) { + blender.write(&dst[x], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+1], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+2], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+3], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+4], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+5], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+6], src[srcx >> 16]); srcx += ix; + blender.write(&dst[x+7], src[srcx >> 16]); srcx += ix; + } + for (; x<w; ++x) { + blender.write(&dst[x], src[srcx >> 16]); + srcx += ix; + } + blender.flush(&dst[x]); + dst = (quint16 *)(((uchar *) dst) + dbpl); + srcy += iy; + } +} + +template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &srcRect, + const QRect &clip, + T blender) +{ + qreal sx = targetRect.width() / (qreal) srcRect.width(); + qreal sy = targetRect.height() / (qreal) srcRect.height(); + + int ix = 0x00010000 / sx; + int iy = 0x00010000 / sy; + +// qDebug() << "scale:" << endl +// << " - target" << targetRect << endl +// << " - source" << srcRect << endl +// << " - clip" << clip << endl +// << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy; + + int cx1 = clip.x(); + int cx2 = clip.x() + clip.width(); + int cy1 = clip.top(); + int cy2 = clip.y() + clip.height(); + + int tx1 = qRound(targetRect.left()); + int tx2 = qRound(targetRect.right()); + int ty1 = qRound(targetRect.top()); + int ty2 = qRound(targetRect.bottom()); + + if (tx2 < tx1) + qSwap(tx2, tx1); + + if (ty2 < ty1) + qSwap(ty2, ty1); + + if (tx1 < cx1) + tx1 = cx1; + + if (tx2 >= cx2) + tx2 = cx2; + + if (tx1 >= tx2) + return; + + if (ty1 < cy1) + ty1 = cy1; + + if (ty2 >= cy2) + ty2 = cy2; + + if (ty1 >= ty2) + return; + + int h = ty2 - ty1; + int w = tx2 - tx1; + + quint32 basex; + quint32 srcy; + + if (sx < 0) { + int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; + basex = quint32(srcRect.right() * 65536) + dstx; + } else { + int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; + basex = quint32(srcRect.left() * 65536) + dstx; + } + if (sy < 0) { + int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; + srcy = quint32(srcRect.bottom() * 65536) + dsty; + } else { + int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; + srcy = quint32(srcRect.top() * 65536) + dsty; + } + + quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1; + + while (h--) { + const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl); + int srcx = basex; + int x = 0; + for (; x<w; ++x) { + blender.write(&dst[x], src[srcx >> 16]); + srcx += ix; + } + blender.flush(&dst[x]); + dst = (quint32 *)(((uchar *) dst) + dbpl); + srcy += iy; + } +} + +struct QTransformImageVertex +{ + qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v) +}; + +template <class SrcT, class DestT, class Blender> +void qt_transform_image_rasterize(DestT *destPixels, int dbpl, + const SrcT *srcPixels, int sbpl, + const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft, + const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight, + const QRect &sourceRect, + const QRect &clip, + qreal topY, qreal bottomY, + int dudx, int dvdx, int dudy, int dvdy, int u0, int v0, + Blender blender) +{ + int fromY = qMax(qRound(topY), clip.top()); + int toY = qMin(qRound(bottomY), clip.top() + clip.height()); + if (fromY >= toY) + return; + + qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y); + qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y); + int dx_l = int(leftSlope * 0x10000); + int dx_r = int(rightSlope * 0x10000); + int x_l = int((topLeft.x + (0.5 + fromY - topLeft.y) * leftSlope + 0.5) * 0x10000); + int x_r = int((topRight.x + (0.5 + fromY - topRight.y) * rightSlope + 0.5) * 0x10000); + + int fromX, toX, x1, x2, u, v, i, ii; + DestT *line; + for (int y = fromY; y < toY; ++y) { + line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl); + + fromX = qMax(x_l >> 16, clip.left()); + toX = qMin(x_r >> 16, clip.left() + clip.width()); + if (fromX < toX) { + // Because of rounding, we can get source coordinates outside the source image. + // Clamp these coordinates to the source rect to avoid segmentation fault and + // garbage on the screen. + + // Find the first pixel on the current scan line where the source coordinates are within the source rect. + x1 = fromX; + u = x1 * dudx + y * dudy + u0; + v = x1 * dvdx + y * dvdy + v0; + for (; x1 < toX; ++x1) { + int uu = u >> 16; + int vv = v >> 16; + if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width() + && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) { + break; + } + u += dudx; + v += dvdx; + } + + // Find the last pixel on the current scan line where the source coordinates are within the source rect. + x2 = toX; + u = (x2 - 1) * dudx + y * dudy + u0; + v = (x2 - 1) * dvdx + y * dvdy + v0; + for (; x2 > x1; --x2) { + int uu = u >> 16; + int vv = v >> 16; + if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width() + && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) { + break; + } + u -= dudx; + v -= dvdx; + } + + // Set up values at the beginning of the scan line. + u = fromX * dudx + y * dudy + u0; + v = fromX * dvdx + y * dvdy + v0; + line += fromX; + + // Beginning of the scan line, with per-pixel checks. + i = x1 - fromX; + while (i) { + int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1); + int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1); + blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); + u += dudx; + v += dvdx; + ++line; + --i; + } + + // Middle of the scan line, without checks. + // Manual loop unrolling. + i = x2 - x1; + ii = i >> 3; + while (ii) { + blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; + + line += 8; + + --ii; + } + switch (i & 7) { + case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line; + } + + // End of the scan line, with per-pixel checks. + i = toX - x2; + while (i) { + int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1); + int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1); + blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]); + u += dudx; + v += dvdx; + ++line; + --i; + } + + blender.flush(line); + } + x_l += dx_l; + x_r += dx_r; + } +} + +template <class SrcT, class DestT, class Blender> +void qt_transform_image(DestT *destPixels, int dbpl, + const SrcT *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + Blender blender) +{ + enum Corner + { + TopLeft, + TopRight, + BottomRight, + BottomLeft + }; + + // map source rectangle to destination. + QTransformImageVertex v[4]; + v[TopLeft].u = v[BottomLeft].u = sourceRect.left(); + v[TopLeft].v = v[TopRight].v = sourceRect.top(); + v[TopRight].u = v[BottomRight].u = sourceRect.right(); + v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom(); + targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y); + targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y); + targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y); + targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y); + + // find topmost vertex. + int topmost = 0; + for (int i = 1; i < 4; ++i) { + if (v[i].y < v[topmost].y) + topmost = i; + } + // rearrange array such that topmost vertex is at index 0. + switch (topmost) { + case 1: + { + QTransformImageVertex t = v[0]; + for (int i = 0; i < 3; ++i) + v[i] = v[i+1]; + v[3] = t; + } + break; + case 2: + qSwap(v[0], v[2]); + qSwap(v[1], v[3]); + break; + case 3: + { + QTransformImageVertex t = v[3]; + for (int i = 3; i > 0; --i) + v[i] = v[i-1]; + v[0] = t; + } + break; + } + + // if necessary, swap vertex 1 and 3 such that 1 is to the left of 3. + qreal dx1 = v[1].x - v[0].x; + qreal dy1 = v[1].y - v[0].y; + qreal dx2 = v[3].x - v[0].x; + qreal dy2 = v[3].y - v[0].y; + if (dx1 * dy2 - dx2 * dy1 > 0) + qSwap(v[1], v[3]); + + QTransformImageVertex u = {v[1].x - v[0].x, v[1].y - v[0].y, v[1].u - v[0].u, v[1].v - v[0].v}; + QTransformImageVertex w = {v[2].x - v[0].x, v[2].y - v[0].y, v[2].u - v[0].u, v[2].v - v[0].v}; + + qreal det = u.x * w.y - u.y * w.x; + if (det == 0) + return; + + qreal invDet = 1.0 / det; + qreal m11, m12, m21, m22, mdx, mdy; + + m11 = (u.u * w.y - u.y * w.u) * invDet; + m12 = (u.x * w.u - u.u * w.x) * invDet; + m21 = (u.v * w.y - u.y * w.v) * invDet; + m22 = (u.x * w.v - u.v * w.x) * invDet; + mdx = v[0].u - m11 * v[0].x - m12 * v[0].y; + mdy = v[0].v - m21 * v[0].x - m22 * v[0].y; + + int dudx = int(m11 * 0x10000); + int dvdx = int(m21 * 0x10000); + int dudy = int(m12 * 0x10000); + int dvdy = int(m22 * 0x10000); + int u0 = qCeil((0.5 * m11 + 0.5 * m12 + mdx) * 0x10000) - 1; + int v0 = qCeil((0.5 * m21 + 0.5 * m22 + mdy) * 0x10000) - 1; + + int x1 = qFloor(sourceRect.left()); + int y1 = qFloor(sourceRect.top()); + int x2 = qCeil(sourceRect.right()); + int y2 = qCeil(sourceRect.bottom()); + QRect sourceRectI(x1, y1, x2 - x1, y2 - y1); + + // rasterize trapezoids. + if (v[1].y < v[3].y) { + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[0], v[3], sourceRectI, clip, v[1].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[3].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + } else { + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[3], v[2], sourceRectI, clip, v[3].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[1].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender); + } +} + +QT_END_NAMESPACE + +#endif // QBLENDFUNCTIONS_P_H diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 1f75ec7..917b910 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -175,7 +175,7 @@ Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuf # define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg> -static const DestFetchProc destFetchProc[QImage::NImageFormats] = +static DestFetchProc destFetchProc[QImage::NImageFormats] = { 0, // Format_Invalid destFetchMono, // Format_Mono, @@ -323,7 +323,7 @@ Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffe # define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST> -static const DestStoreProc destStoreProc[QImage::NImageFormats] = +static DestStoreProc destStoreProc[QImage::NImageFormats] = { 0, // Format_Invalid destStoreMono, // Format_Mono, @@ -2827,7 +2827,7 @@ static void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest, } } -static const CompositionFunctionSolid functionForModeSolid_C[] = { +static CompositionFunctionSolid functionForModeSolid_C[] = { comp_func_solid_SourceOver, comp_func_solid_DestinationOver, comp_func_solid_Clear, @@ -2865,7 +2865,7 @@ static const CompositionFunctionSolid functionForModeSolid_C[] = { static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C; -static const CompositionFunction functionForMode_C[] = { +static CompositionFunction functionForMode_C[] = { comp_func_SourceOver, comp_func_DestinationOver, comp_func_Clear, @@ -7961,6 +7961,20 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB16] = qt_blend_rgb16_on_argb32_neon; + + qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16_neon; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16_neon; + + qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16_neon; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16_neon; + + qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; + + functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; + destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; + destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; } #endif diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 77c5202..ee5f24a 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -40,10 +40,13 @@ ****************************************************************************/ #include <private/qdrawhelper_p.h> +#include <private/qblendfunctions_p.h> +#include <private/qmath_p.h> #ifdef QT_HAVE_NEON #include <private/qdrawhelper_neon_p.h> +#include <private/qpaintengine_raster_p.h> #include <arm_neon.h> QT_BEGIN_NAMESPACE @@ -87,60 +90,142 @@ static inline uint16x8_t qvsource_over_u16(uint16x8_t src16, uint16x8_t dst16, u return vaddq_u16(src16, qvbyte_mul_u16(dst16, alpha16, half)); } -void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +extern "C" void +pixman_composite_over_8888_0565_asm_neon (int32_t w, + int32_t h, + uint16_t *dst, + int32_t dst_stride, + uint32_t *src, + int32_t src_stride); + +extern "C" void +pixman_composite_over_8888_8888_asm_neon (int32_t w, + int32_t h, + uint32_t *dst, + int32_t dst_stride, + uint32_t *src, + int32_t src_stride); + +extern "C" void +pixman_composite_src_0565_8888_asm_neon (int32_t w, + int32_t h, + uint32_t *dst, + int32_t dst_stride, + uint16_t *src, + int32_t src_stride); + +extern "C" void +pixman_composite_over_n_8_0565_asm_neon (int32_t w, + int32_t h, + uint16_t *dst, + int32_t dst_stride, + uint32_t src, + int32_t unused, + uint8_t *mask, + int32_t mask_stride); + +extern "C" void +pixman_composite_scanline_over_asm_neon (int32_t w, + const uint32_t *dst, + const uint32_t *src); + +// qblendfunctions.cpp +void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { - const uint *src = (const uint *) srcPixels; - uint *dst = (uint *) destPixels; - uint16x8_t half = vdupq_n_u16(0x80); - uint16x8_t full = vdupq_n_u16(0xff); - if (const_alpha == 256) { - for (int y = 0; y < h; ++y) { - int x = 0; - for (; x < w-3; x += 4) { - uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]); - if ((src[x] & src[x+1] & src[x+2] & src[x+3]) >= 0xff000000) { - // all opaque - vst1q_u32((uint32_t *)&dst[x], src32); - } else if (src[x] | src[x+1] | src[x+2] | src[x+3]) { - uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]); + dbpl /= 4; + sbpl /= 2; - const uint8x16_t src8 = vreinterpretq_u8_u32(src32); - const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32); + quint32 *dst = (quint32 *) destPixels; + quint16 *src = (quint16 *) srcPixels; - const uint8x8_t src8_low = vget_low_u8(src8); - const uint8x8_t dst8_low = vget_low_u8(dst8); + if (const_alpha != 256) { + quint8 a = (255 * const_alpha) >> 8; + quint8 ia = 255 - a; + + while (h--) { + for (int x=0; x<w; ++x) + dst[x] = INTERPOLATE_PIXEL_255(qt_colorConvert(src[x], dst[x]), a, dst[x], ia); + dst += dbpl; + src += sbpl; + } + return; + } - const uint8x8_t src8_high = vget_high_u8(src8); - const uint8x8_t dst8_high = vget_high_u8(dst8); + pixman_composite_src_0565_8888_asm_neon(w, h, dst, dbpl, src, sbpl); +} - const uint16x8_t src16_low = vmovl_u8(src8_low); - const uint16x8_t dst16_low = vmovl_u8(dst8_low); +extern "C" void blend_8_pixels_argb32_on_rgb16_neon(quint16 *dst, const quint32 *src, int const_alpha); - const uint16x8_t src16_high = vmovl_u8(src8_high); - const uint16x8_t dst16_high = vmovl_u8(dst8_high); +void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + quint16 *dst = (quint16 *) destPixels; + quint32 *src = (quint32 *) srcPixels; - const uint16x8_t result16_low = qvsource_over_u16(src16_low, dst16_low, half, full); - const uint16x8_t result16_high = qvsource_over_u16(src16_high, dst16_high, half, full); + if (const_alpha != 256) { + for (int y=0; y<h; ++y) { + int i = 0; + for (; i < w-7; i += 8) + blend_8_pixels_argb32_on_rgb16_neon(&dst[i], &src[i], const_alpha); - const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low)); - const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high)); + if (i < w) { + int tail = w - i; - vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high)); + quint16 dstBuffer[8]; + quint32 srcBuffer[8]; + + for (int j = 0; j < tail; ++j) { + dstBuffer[j] = dst[i + j]; + srcBuffer[j] = src[i + j]; + } + + blend_8_pixels_argb32_on_rgb16_neon(dstBuffer, srcBuffer, const_alpha); + + for (int j = 0; j < tail; ++j) { + dst[i + j] = dstBuffer[j]; + src[i + j] = srcBuffer[j]; } } - 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)); - } - dst = (quint32 *)(((uchar *) dst) + dbpl); - src = (const quint32 *)(((const uchar *) src) + sbpl); + + dst = (quint16 *)(((uchar *) dst) + dbpl); + src = (quint32 *)(((uchar *) src) + sbpl); } + return; + } + + pixman_composite_over_8888_0565_asm_neon(w, h, dst, dbpl / 2, src, sbpl / 4); +} + +void qt_blend_argb32_on_argb32_scanline_neon(uint *dest, const uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + pixman_composite_scanline_over_asm_neon(length, dest, src); + } else { + qt_blend_argb32_on_argb32_neon((uchar *)dest, 4 * length, (uchar *)src, 4 * length, length, 1, (const_alpha * 256) / 255); + } +} + +void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + const uint *src = (const uint *) srcPixels; + uint *dst = (uint *) destPixels; + uint16x8_t half = vdupq_n_u16(0x80); + uint16x8_t full = vdupq_n_u16(0xff); + if (const_alpha == 256) { + pixman_composite_over_8888_8888_asm_neon(w, h, (uint32_t *)destPixels, dbpl / 4, (uint32_t *)srcPixels, sbpl / 4); } else if (const_alpha != 0) { const_alpha = (const_alpha * 255) >> 8; uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha); @@ -254,6 +339,246 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, } } +void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer, + int x, int y, quint32 color, + const uchar *bitmap, + int mapWidth, int mapHeight, int mapStride, + const QClipData *) +{ + quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x; + const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16); + + uchar *mask = const_cast<uchar *>(bitmap); + + pixman_composite_over_n_8_0565_asm_neon(mapWidth, mapHeight, dest, destStride, color, 0, mask, mapStride); +} + +extern "C" void blend_8_pixels_rgb16_on_rgb16_neon(quint16 *dst, const quint16 *src, int const_alpha); + +template <typename SRC, typename BlendFunc> +struct Blend_on_RGB16_SourceAndConstAlpha_Neon { + Blend_on_RGB16_SourceAndConstAlpha_Neon(BlendFunc blender, int const_alpha) + : m_index(0) + , m_blender(blender) + , m_const_alpha(const_alpha) + { + } + + inline void write(quint16 *dst, quint32 src) + { + srcBuffer[m_index++] = src; + + if (m_index == 8) { + m_blender(dst - 7, srcBuffer, m_const_alpha); + m_index = 0; + } + } + + inline void flush(quint16 *dst) + { + if (m_index > 0) { + quint16 dstBuffer[8]; + for (int i = 0; i < m_index; ++i) + dstBuffer[i] = dst[i - m_index]; + + m_blender(dstBuffer, srcBuffer, m_const_alpha); + + for (int i = 0; i < m_index; ++i) + dst[i - m_index] = dstBuffer[i]; + + m_index = 0; + } + } + + SRC srcBuffer[8]; + + int m_index; + BlendFunc m_blender; + int m_const_alpha; +}; + +template <typename SRC, typename BlendFunc> +Blend_on_RGB16_SourceAndConstAlpha_Neon<SRC, BlendFunc> +Blend_on_RGB16_SourceAndConstAlpha_Neon_create(BlendFunc blender, int const_alpha) +{ + return Blend_on_RGB16_SourceAndConstAlpha_Neon<SRC, BlendFunc>(blender, const_alpha); +} + +void qt_scale_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha) +{ + if (const_alpha == 0) + return; + + qt_scale_image_16bit<quint32>(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, + Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint32>(blend_8_pixels_argb32_on_rgb16_neon, const_alpha)); +} + +void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha); + +void qt_scale_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha) +{ + if (const_alpha == 0) + return; + + if (const_alpha == 256) { + qt_scale_image_rgb16_on_rgb16(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, const_alpha); + return; + } + + qt_scale_image_16bit<quint16>(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, + Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint16>(blend_8_pixels_rgb16_on_rgb16_neon, const_alpha)); +} + +extern void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + int const_alpha); + +void qt_transform_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + int const_alpha) +{ + if (const_alpha == 0) + return; + + if (const_alpha == 256) { + qt_transform_image_rgb16_on_rgb16(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, targetRectTransform, const_alpha); + return; + } + + qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl, + reinterpret_cast<const quint16 *>(srcPixels), sbpl, targetRect, sourceRect, clip, targetRectTransform, + Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint16>(blend_8_pixels_rgb16_on_rgb16_neon, const_alpha)); +} + +void qt_transform_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + int const_alpha) +{ + if (const_alpha == 0) + return; + + qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl, + reinterpret_cast<const quint32 *>(srcPixels), sbpl, targetRect, sourceRect, clip, targetRectTransform, + Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint32>(blend_8_pixels_argb32_on_rgb16_neon, const_alpha)); +} + +static inline void convert_8_pixels_rgb16_to_argb32(quint32 *dst, const quint16 *src) +{ + asm volatile ( + "vld1.16 { d0, d1 }, [%[SRC]]\n\t" + + /* convert 8 r5g6b5 pixel data from {d0, d1} to planar 8-bit format + and put data into d4 - red, d3 - green, d2 - blue */ + "vshrn.u16 d4, q0, #8\n\t" + "vshrn.u16 d3, q0, #3\n\t" + "vsli.u16 q0, q0, #5\n\t" + "vsri.u8 d4, d4, #5\n\t" + "vsri.u8 d3, d3, #6\n\t" + "vshrn.u16 d2, q0, #2\n\t" + + /* fill d5 - alpha with 0xff */ + "mov r2, #255\n\t" + "vdup.8 d5, r2\n\t" + + "vst4.8 { d2, d3, d4, d5 }, [%[DST]]" + : : [DST]"r" (dst), [SRC]"r" (src) + : "memory", "r2", "d0", "d1", "d2", "d3", "d4", "d5" + ); +} + +uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +{ + const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x; + + int i = 0; + for (; i < length - 7; i += 8) + convert_8_pixels_rgb16_to_argb32(&buffer[i], &data[i]); + + if (i < length) { + quint16 srcBuffer[8]; + quint32 dstBuffer[8]; + + int tail = length - i; + for (int j = 0; j < tail; ++j) + srcBuffer[j] = data[i + j]; + + convert_8_pixels_rgb16_to_argb32(dstBuffer, srcBuffer); + + for (int j = 0; j < tail; ++j) + buffer[i + j] = dstBuffer[j]; + } + + return buffer; +} + +static inline void convert_8_pixels_argb32_to_rgb16(quint16 *dst, const quint32 *src) +{ + asm volatile ( + "vld4.8 { d0, d1, d2, d3 }, [%[SRC]]\n\t" + + /* convert to r5g6b5 and store it into {d28, d29} */ + "vshll.u8 q14, d2, #8\n\t" + "vshll.u8 q8, d1, #8\n\t" + "vshll.u8 q9, d0, #8\n\t" + "vsri.u16 q14, q8, #5\n\t" + "vsri.u16 q14, q9, #11\n\t" + + "vst1.16 { d28, d29 }, [%[DST]]" + : : [DST]"r" (dst), [SRC]"r" (src) + : "memory", "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19", "d28", "d29" + ); +} + +void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length) +{ + quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x; + + int i = 0; + for (; i < length - 7; i += 8) + convert_8_pixels_argb32_to_rgb16(&data[i], &buffer[i]); + + if (i < length) { + quint32 srcBuffer[8]; + quint16 dstBuffer[8]; + + int tail = length - i; + for (int j = 0; j < tail; ++j) + srcBuffer[j] = buffer[i + j]; + + convert_8_pixels_argb32_to_rgb16(dstBuffer, srcBuffer); + + for (int j = 0; j < tail; ++j) + data[i + j] = dstBuffer[j]; + } +} + 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 new file mode 100644 index 0000000..9992817 --- /dev/null +++ b/src/gui/painting/qdrawhelper_neon_asm.S @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* Prevent the stack from becoming executable for no reason... */ +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +.text +.fpu neon +.arch armv7a +.altmacro + +/* void blend_8_pixels_argb32_on_rgb16_neon(quint16 *dst, const quint32 *src, int const_alpha) */ + + .func blend_8_pixels_argb32_on_rgb16_neon + .global blend_8_pixels_argb32_on_rgb16_neon + /* For ELF format also set function visibility to hidden */ +#ifdef __ELF__ + .hidden blend_8_pixels_argb32_on_rgb16_neon + .type blend_8_pixels_argb32_on_rgb16_neon, %function +#endif +blend_8_pixels_argb32_on_rgb16_neon: + vld4.8 { d0, d1, d2, d3 }, [r1] + vld1.16 { d4, d5 }, [r0] + + cmp r2, #256 + beq .blend_32_inner + + vdup.8 d6, r2 + + /* multiply by const_alpha */ + vmull.u8 q8, d6, d0 + vmull.u8 q9, d6, d1 + vmull.u8 q10, d6, d2 + vmull.u8 q11, d6, d3 + + vshrn.u16 d0, q8, #8 + vshrn.u16 d1, q9, #8 + vshrn.u16 d2, q10, #8 + vshrn.u16 d3, q11, #8 + +.blend_32_inner: + /* convert 8 r5g6b5 pixel data from {d4, d5} to planar 8-bit format + and put data into d6 - red, d7 - green, d30 - blue */ + vshrn.u16 d6, q2, #8 + vshrn.u16 d7, q2, #3 + vsli.u16 q2, q2, #5 + vsri.u8 d6, d6, #5 + vmvn.8 d3, d3 + vsri.u8 d7, d7, #6 + vshrn.u16 d30, q2, #2 + + pld [r0, #128] + + /* now do alpha blending, storing results in 8-bit planar format + into d16 - red, d19 - green, d18 - blue */ + vmull.u8 q10, d3, d6 + vmull.u8 q11, d3, d7 + vmull.u8 q12, d3, d30 + vrshr.u16 q13, q10, #8 + vrshr.u16 q3, q11, #8 + vrshr.u16 q15, q12, #8 + vraddhn.u16 d20, q10, q13 + vraddhn.u16 d23, q11, q3 + vraddhn.u16 d22, q12, q15 + vqadd.u8 d16, d2, d20 + vqadd.u8 q9, q0, q11 + /* convert the result to r5g6b5 and store it into {d28, d29} */ + vshll.u8 q14, d16, #8 + vshll.u8 q8, d19, #8 + vshll.u8 q9, d18, #8 + vsri.u16 q14, q8, #5 + vsri.u16 q14, q9, #11 + + vst1.16 { d28, d29 }, [r0] + + bx lr + + .endfunc + +/* void blend_8_pixels_rgb16_on_rgb16_neon(quint16 *dst, const quint16 *src, int const_alpha) */ + + .func blend_8_pixels_rgb16_on_rgb16_neon + .global blend_8_pixels_rgb16_on_rgb16_neon + /* For ELF format also set function visibility to hidden */ +#ifdef __ELF__ + .hidden blend_8_pixels_rgb16_on_rgb16_neon + .type blend_8_pixels_rgb16_on_rgb16_neon, %function +#endif +blend_8_pixels_rgb16_on_rgb16_neon: + vld1.16 { d0, d1 }, [r0] + vld1.16 { d2, d3 }, [r1] + + rsb r3, r2, #256 + vdup.8 d4, r2 + vdup.8 d5, r3 + + /* convert 8 r5g6b5 pixel data from {d0, d1} to planar 8-bit format + and put data into d6 - red, d7 - green, d30 - blue */ + vshrn.u16 d6, q0, #8 + vshrn.u16 d7, q0, #3 + vsli.u16 q0, q0, #5 + vsri.u8 d6, d6, #5 + vsri.u8 d7, d7, #6 + vshrn.u16 d30, q0, #2 + + /* same from {d2, d3} into {d26, d27, d28} */ + vshrn.u16 d26, q1, #8 + vshrn.u16 d27, q1, #3 + vsli.u16 q1, q1, #5 + vsri.u8 d26, d26, #5 + vsri.u8 d27, d27, #6 + vshrn.u16 d28, q1, #2 + + /* multiply dst by inv const_alpha */ + vmull.u8 q10, d5, d6 + vmull.u8 q11, d5, d7 + vmull.u8 q12, d5, d30 + + vshrn.u16 d6, q10, #8 + vshrn.u16 d7, q11, #8 + vshrn.u16 d30, q12, #8 + + /* multiply src by const_alpha */ + vmull.u8 q10, d4, d26 + vmull.u8 q11, d4, d27 + vmull.u8 q12, d4, d28 + + vshrn.u16 d26, q10, #8 + vshrn.u16 d27, q11, #8 + vshrn.u16 d28, q12, #8 + + /* preload dst + 128 */ + pld [r0, #128] + + /* add components, storing results in 8-bit planar format + into d16 - red, d19 - green, d18 - blue */ + vadd.u8 d16, d26, d6 + vadd.u8 d19, d27, d7 + vadd.u8 d18, d28, d30 + + /* convert the result to r5g6b5 and store it into {d28, d29} */ + vshll.u8 q14, d16, #8 + vshll.u8 q8, d19, #8 + vshll.u8 q9, d18, #8 + vsri.u16 q14, q8, #5 + vsri.u16 q14, q9, #11 + + vst1.16 { d28, d29 }, [r0] + + bx lr + + .endfunc diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h index 1994441..d6a4509 100644 --- a/src/gui/painting/qdrawhelper_neon_p.h +++ b/src/gui/painting/qdrawhelper_neon_p.h @@ -69,6 +69,64 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, int w, int h, int const_alpha); +void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_blend_argb32_on_argb32_scanline_neon(uint *dest, + const uint *src, + int length, + uint const_alpha); + +void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer, + int x, int y, quint32 color, + const uchar *bitmap, + int mapWidth, int mapHeight, int mapStride, + const QClipData *clip); + +void qt_scale_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha); + +void qt_scale_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + int const_alpha); + +void qt_transform_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + int const_alpha); + +void qt_transform_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + const QRectF &targetRect, + const QRectF &sourceRect, + const QRect &clip, + const QTransform &targetRectTransform, + int const_alpha); + +uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer, + QRasterBuffer *rasterBuffer, + int x, int y, int length); + +void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer, + int x, int y, const uint *buffer, int length); + #endif // QT_HAVE_NEON QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 39b76c8..ca2077f 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -269,24 +269,304 @@ void QPaintBuffer::draw(QPainter *painter, int frame) const printf("\n"); #endif - if (painter && !painter->isActive()) - return; + processCommands(painter, frameStartIndex(frame), frameEndIndex(frame)); + +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBuffer::draw() -------------------------------- DONE!"; +#endif +} + +int QPaintBuffer::frameStartIndex(int frame) const +{ + return (frame == 0) ? 0 : d_ptr->frames.at(frame - 1); +} + +int QPaintBuffer::frameEndIndex(int frame) const +{ + return (frame == d_ptr->frames.size()) ? d_ptr->commands.size() : d_ptr->frames.at(frame); +} + +int QPaintBuffer::processCommands(QPainter *painter, int begin, int end) const +{ + if (!painter || !painter->isActive()) + return 0; QPaintEngineEx *xengine = painter->paintEngine()->isExtended() ? (QPaintEngineEx *) painter->paintEngine() : 0; if (xengine) { QPaintEngineExReplayer player; - player.draw(*this, painter, frame); + player.processCommands(*this, painter, begin, end); } else { QPainterReplayer player; - player.draw(*this, painter, frame); + player.processCommands(*this, painter, begin, end); } -#ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBuffer::draw() -------------------------------- DONE!"; -#endif + int depth = 0; + for (int i = begin; i < end; ++i) { + const QPaintBufferCommand &cmd = d_ptr->commands.at(i); + if (cmd.id == QPaintBufferPrivate::Cmd_Save) + ++depth; + else if (cmd.id == QPaintBufferPrivate::Cmd_Restore) + --depth; + } + return depth; } +QString QPaintBuffer::commandDescription(int command) const +{ + QString desc; + QDebug debug(&desc); + + const QPaintBufferCommand &cmd = d_ptr->commands.at(command); + + switch (cmd.id) { + case QPaintBufferPrivate::Cmd_Save: { + debug << "Cmd_Save"; + break; } + + case QPaintBufferPrivate::Cmd_Restore: { + debug << "Cmd_Restore"; + break; } + + case QPaintBufferPrivate::Cmd_SetBrush: { + QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.offset)); + debug << "Cmd_SetBrush: " << brush; + break; } + + case QPaintBufferPrivate::Cmd_SetBrushOrigin: { + debug << "Cmd_SetBrushOrigin: " << d_ptr->variants.at(cmd.offset).toPointF(); + break; } + + case QPaintBufferPrivate::Cmd_SetCompositionMode: { + QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra; + debug << "ExCmd_SetCompositionMode, mode: " << mode; + break; } + + case QPaintBufferPrivate::Cmd_SetOpacity: { + debug << "ExCmd_SetOpacity: " << d_ptr->variants.at(cmd.offset).toDouble(); + break; } + + case QPaintBufferPrivate::Cmd_DrawVectorPath: { + debug << "ExCmd_DrawVectorPath: size: " << cmd.size +// << ", hints:" << d->ints[cmd.offset2+cmd.size] + << "pts/elms:" << cmd.offset << cmd.offset2; + break; } + + case QPaintBufferPrivate::Cmd_StrokeVectorPath: { + QPen pen = qVariantValue<QPen>(d_ptr->variants.at(cmd.extra)); + debug << "ExCmd_StrokeVectorPath: size: " << cmd.size +// << ", hints:" << d->ints[cmd.offset2+cmd.size] + << "pts/elms:" << cmd.offset << cmd.offset2 << pen; + break; } + + case QPaintBufferPrivate::Cmd_FillVectorPath: { + QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.extra)); + debug << "ExCmd_FillVectorPath: size: " << cmd.size +// << ", hints:" << d->ints[cmd.offset2+cmd.size] + << "pts/elms:" << cmd.offset << cmd.offset2 << brush; + break; } + + case QPaintBufferPrivate::Cmd_FillRectBrush: { + QBrush brush = qVariantValue<QBrush>(d_ptr->variants.at(cmd.extra)); + QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); + debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush; + break; } + + case QPaintBufferPrivate::Cmd_FillRectColor: { + QColor color = qVariantValue<QColor>(d_ptr->variants.at(cmd.extra)); + QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset); + debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color; + break; } + + case QPaintBufferPrivate::Cmd_DrawPolygonF: { + debug << "ExCmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size + << " mode: " << cmd.extra + << d_ptr->floats.at(cmd.offset) + << d_ptr->floats.at(cmd.offset+1); + break; } + + case QPaintBufferPrivate::Cmd_DrawPolygonI: { + debug << "ExCmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size + << " mode: " << cmd.extra + << d_ptr->ints.at(cmd.offset) + << d_ptr->ints.at(cmd.offset+1); + break; } + + case QPaintBufferPrivate::Cmd_DrawEllipseF: { + debug << "ExCmd_DrawEllipseF, offset: " << cmd.offset; + break; } + + case QPaintBufferPrivate::Cmd_DrawLineF: { + debug << "ExCmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawLineI: { + debug << "ExCmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawPointsF: { + debug << "ExCmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawPointsI: { + debug << "ExCmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawPolylineF: { + debug << "ExCmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawPolylineI: { + debug << "ExCmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawRectF: { + debug << "ExCmd_DrawRectF, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawRectI: { + debug << "ExCmd_DrawRectI, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_SetClipEnabled: { + bool clipEnabled = d_ptr->variants.at(cmd.offset).toBool(); + debug << "ExCmd_SetClipEnabled:" << clipEnabled; + break; } + + case QPaintBufferPrivate::Cmd_ClipVectorPath: { + QVectorPathCmd path(d_ptr, cmd); + debug << "ExCmd_ClipVectorPath:" << path().elementCount(); + break; } + + case QPaintBufferPrivate::Cmd_ClipRect: { + QRect rect(QPoint(d_ptr->ints.at(cmd.offset), d_ptr->ints.at(cmd.offset + 1)), + QPoint(d_ptr->ints.at(cmd.offset + 2), d_ptr->ints.at(cmd.offset + 3))); + debug << "ExCmd_ClipRect:" << rect << cmd.extra; + break; } + + case QPaintBufferPrivate::Cmd_ClipRegion: { + QRegion region(d_ptr->variants.at(cmd.offset).value<QRegion>()); + debug << "ExCmd_ClipRegion:" << region.boundingRect() << cmd.extra; + break; } + + case QPaintBufferPrivate::Cmd_SetPen: { + QPen pen = qVariantValue<QPen>(d_ptr->variants.at(cmd.offset)); + debug << "Cmd_SetPen: " << pen; + break; } + + case QPaintBufferPrivate::Cmd_SetTransform: { + QTransform xform = qVariantValue<QTransform>(d_ptr->variants.at(cmd.offset)); + debug << "Cmd_SetTransform, offset: " << cmd.offset << xform; + break; } + + case QPaintBufferPrivate::Cmd_SetRenderHints: { + debug << "Cmd_SetRenderHints, hints: " << cmd.extra; + break; } + + case QPaintBufferPrivate::Cmd_SetBackgroundMode: { + debug << "Cmd_SetBackgroundMode: " << cmd.extra; + break; } + + case QPaintBufferPrivate::Cmd_DrawConvexPolygonF: { + debug << "Cmd_DrawConvexPolygonF, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawConvexPolygonI: { + debug << "Cmd_DrawConvexPolygonI, offset: " << cmd.offset << " size: " << cmd.size; + break; } + + case QPaintBufferPrivate::Cmd_DrawEllipseI: { + debug << "Cmd_DrawEllipseI, offset: " << cmd.offset; + break; } + + case QPaintBufferPrivate::Cmd_DrawPixmapRect: { + QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>()); + QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), + d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); + + QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5), + d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7)); + debug << "Cmd_DrawPixmapRect:" << r << sr << pm.size(); + break; } + + case QPaintBufferPrivate::Cmd_DrawPixmapPos: { + QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>()); + QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + debug << "Cmd_DrawPixmapPos:" << pos << pm.size(); + break; } + + case QPaintBufferPrivate::Cmd_DrawTiledPixmap: { + QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>()); + QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), + d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); + + QPointF offset(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5)); + debug << "Cmd_DrawTiledPixmap:" << r << offset << pm.size(); + break; } + + case QPaintBufferPrivate::Cmd_DrawImageRect: { + QImage image(d_ptr->variants.at(cmd.offset).value<QImage>()); + QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1), + d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3)); + QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5), + d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7)); + debug << "Cmd_DrawImageRect:" << r << sr << image.size(); + break; } + + case QPaintBufferPrivate::Cmd_DrawImagePos: { + QImage image(d_ptr->variants.at(cmd.offset).value<QImage>()); + QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + debug << "Cmd_DrawImagePos:" << pos << image.size(); + break; } + + case QPaintBufferPrivate::Cmd_DrawText: { + QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + QList<QVariant> variants(d_ptr->variants.at(cmd.offset).value<QList<QVariant> >()); + + QFont font(variants.at(0).value<QFont>()); + QString text(variants.at(1).value<QString>()); + + debug << "Cmd_DrawText:" << pos << text << font.family(); + break; } + + case QPaintBufferPrivate::Cmd_DrawTextItem: { + QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qVariantValue<void *>(d_ptr->variants.at(cmd.offset))); + QTextItemInt &ti = (*tiCopy)(); + QString text(ti.text()); + + QFont font(ti.font()); + font.setUnderline(false); + font.setStrikeOut(false); + font.setOverline(false); + + const QTextItemInt &si = static_cast<const QTextItemInt &>(ti); + qreal justificationWidth = 0; + if (si.justified) + justificationWidth = si.width.toReal(); + + debug << "Cmd_DrawTextItem:" << pos << " " << text; + break; } + case QPaintBufferPrivate::Cmd_SystemStateChanged: { + QRegion systemClip(d_ptr->variants.at(cmd.offset).value<QRegion>()); + + debug << "Cmd_SystemStateChanged:" << systemClip; + break; } + case QPaintBufferPrivate::Cmd_Translate: { + QPointF delta(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + debug << "Cmd_Translate:" << delta; + break; } + case QPaintBufferPrivate::Cmd_DrawStaticText: { + QPointF delta(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); + QVariantList variants(d_ptr->variants.at(cmd.offset).value<QVariantList>()); + + QStaticText text(variants.at(0).value<QStaticText>()); + debug << "Cmd_DrawStaticText:" << text.text(); + break; } + } + + return desc; +} QRectF QPaintBuffer::boundingRect() const { @@ -1110,15 +1390,12 @@ void QPainterReplayer::setupTransform(QPainter *_painter) painter->setTransform(m_world_matrix); } -void QPainterReplayer::draw(const QPaintBuffer &buffer, QPainter *_painter, int frame) +void QPainterReplayer::processCommands(const QPaintBuffer &buffer, QPainter *p, int begin, int end) { d = buffer.d_ptr; - setupTransform(_painter); - - int frameStart = (frame == 0) ? 0 : d->frames.at(frame-1); - int frameEnd = (frame == d->frames.size()) ? d->commands.size() : d->frames.at(frame); + painter = p; - for (int cmdIndex=frameStart; cmdIndex<frameEnd; ++cmdIndex) { + for (int cmdIndex = begin; cmdIndex < end; ++cmdIndex) { const QPaintBufferCommand &cmd = d->commands.at(cmdIndex); process(cmd); } diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index 0fde290..4576947 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -78,6 +78,12 @@ public: int numFrames() const; void draw(QPainter *painter, int frame = 0) const; + + int frameStartIndex(int frame) const; + int frameEndIndex(int frame) const; + int processCommands(QPainter *painter, int begin, int end) const; + QString commandDescription(int command) const; + void setBoundingRect(const QRectF &rect); QRectF boundingRect() const; @@ -317,7 +323,7 @@ public: void setupTransform(QPainter *painter); virtual void process(const QPaintBufferCommand &cmd); - void draw(const QPaintBuffer &buffer, QPainter *painter, int frame); + void processCommands(const QPaintBuffer &buffer, QPainter *painter, int begin, int end); protected: QPaintBufferPrivate *d; diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4f42a58..988d678 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1037,8 +1037,18 @@ QDataStream & operator>>(QDataStream &s, QTransform &t) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QTransform &m) { - dbg.nospace() << "QTransform(" - << "11=" << m.m11() + static const char *typeStr[] = + { + "TxNone", + "TxTranslate", + "TxScale", + "TxRotate", + "TxShear", + "TxProject" + }; + + dbg.nospace() << "QTransform(type=" << typeStr[m.type()] << ',' + << " 11=" << m.m11() << " 12=" << m.m12() << " 13=" << m.m13() << " 21=" << m.m21() @@ -1048,6 +1058,7 @@ QDebug operator<<(QDebug dbg, const QTransform &m) << " 32=" << m.m32() << " 33=" << m.m33() << ')'; + return dbg.space(); } #endif diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 9b85c04..99b9f40 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -1297,6 +1297,8 @@ QFont::StyleHint QFont::styleHint() const \value PreferQuality prefer the best quality font. The font matcher will use the nearest standard point size that the font supports. + \value ForceIntegerMetrics forces the use of integer values in font engines that support fractional + font metrics. */ /*! diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 5adf237..6f62424 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -76,17 +76,18 @@ public: }; enum StyleStrategy { - PreferDefault = 0x0001, - PreferBitmap = 0x0002, - PreferDevice = 0x0004, - PreferOutline = 0x0008, - ForceOutline = 0x0010, - PreferMatch = 0x0020, - PreferQuality = 0x0040, - PreferAntialias = 0x0080, - NoAntialias = 0x0100, - OpenGLCompatible = 0x0200, - NoFontMerging = 0x8000 + PreferDefault = 0x0001, + PreferBitmap = 0x0002, + PreferDevice = 0x0004, + PreferOutline = 0x0008, + ForceOutline = 0x0010, + PreferMatch = 0x0020, + PreferQuality = 0x0040, + PreferAntialias = 0x0080, + NoAntialias = 0x0100, + OpenGLCompatible = 0x0200, + ForceIntegerMetrics = 0x0400, + NoFontMerging = 0x8000 }; enum Weight { diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 8588214..3f84544 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -53,6 +53,7 @@ #include <qvarlengtharray.h> #include <qdebug.h> #include <qendian.h> +#include <qmath.h> #include <ApplicationServices/ApplicationServices.h> #include <AppKit/AppKit.h> @@ -303,12 +304,20 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay outGlyphs[idx] = tmpGlyphs[i] | fontIndex; outAdvances_x[idx] = QFixed::fromReal(tmpPoints[i + 1].x - tmpPoints[i].x); outAdvances_y[idx] = QFixed::fromReal(tmpPoints[i + 1].y - tmpPoints[i].y); + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + outAdvances_x[idx] = outAdvances_x[idx].ceil(); + outAdvances_y[idx] = outAdvances_y[idx].ceil(); + } } CGSize lastGlyphAdvance; CTFontGetAdvancesForGlyphs(runFont, kCTFontHorizontalOrientation, tmpGlyphs + glyphCount - 1, &lastGlyphAdvance, 1); outGlyphs[rtl ? 0 : (glyphCount - 1)] = tmpGlyphs[glyphCount - 1] | fontIndex; - outAdvances_x[rtl ? 0 : (glyphCount - 1)] = QFixed::fromReal(lastGlyphAdvance.width); + outAdvances_x[rtl ? 0 : (glyphCount - 1)] = + (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? QFixed::fromReal(lastGlyphAdvance.width).ceil() + : QFixed::fromReal(lastGlyphAdvance.width); } outGlyphs += glyphCount; outAttributes += glyphCount; @@ -378,8 +387,11 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int * glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) { QFixed w; - for (int i = 0; i < glyphs.numGlyphs; ++i) - w += glyphs.effectiveAdvance(i); + for (int i = 0; i < glyphs.numGlyphs; ++i) { + w += (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? glyphs.effectiveAdvance(i).ceil() + : glyphs.effectiveAdvance(i); + } return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0); } glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) @@ -393,33 +405,51 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) ret.y = -QFixed::fromReal(rect.origin.y) - ret.height; CGSize advances[1]; CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1); - ret.xoff = QFixed::fromReal(advances[0].width).ceil(); - ret.yoff = QFixed::fromReal(advances[0].height).ceil(); + ret.xoff = QFixed::fromReal(advances[0].width); + ret.yoff = QFixed::fromReal(advances[0].height); + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + ret.xoff = ret.xoff.ceil(); + ret.yoff = ret.yoff.ceil(); + } + return ret; } QFixed QCoreTextFontEngine::ascent() const { - return QFixed::fromReal(CTFontGetAscent(ctfont)).ceil(); + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? QFixed::fromReal(CTFontGetAscent(ctfont)).ceil() + : QFixed::fromReal(CTFontGetAscent(ctfont)); } QFixed QCoreTextFontEngine::descent() const { + QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont)); + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + d = d.ceil(); + // subtract a pixel to even out the historical +1 in QFontMetrics::height(). // Fix in Qt 5. - return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil() - 1; + return d - 1; } QFixed QCoreTextFontEngine::leading() const { - return QFixed::fromReal(CTFontGetLeading(ctfont)).ceil(); + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? QFixed::fromReal(CTFontGetLeading(ctfont)).ceil() + : QFixed::fromReal(CTFontGetLeading(ctfont)); } QFixed QCoreTextFontEngine::xHeight() const { - return QFixed::fromReal(CTFontGetXHeight(ctfont)).ceil(); + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? QFixed::fromReal(CTFontGetXHeight(ctfont)).ceil() + : QFixed::fromReal(CTFontGetXHeight(ctfont)); } QFixed QCoreTextFontEngine::averageCharWidth() const { // ### Need to implement properly and get the information from the OS/2 Table. - return QFontEngine::averageCharWidth(); + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? QFontEngine::averageCharWidth().ceil() + : QFontEngine::averageCharWidth(); } qreal QCoreTextFontEngine::maxCharWidth() const @@ -787,6 +817,7 @@ struct QGlyphLayoutInfo int *mappedFonts; QTextEngine::ShaperFlags flags; QFontEngineMacMulti::ShaperItem *shaperItem; + unsigned int styleStrategy; }; static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATSULineRef lineRef, URefCon refCon, @@ -856,6 +887,11 @@ static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATS QFixed yAdvance = FixedToQFixed(baselineDeltas[glyphIdx]); QFixed xAdvance = FixedToQFixed(layoutData[glyphIdx + 1].realPos - layoutData[glyphIdx].realPos); + if (nfo->styleStrategy & QFont::ForceIntegerMetrics) { + yAdvance = yAdvance.ceil(); + xAdvance = xAdvance.ceil(); + } + if (glyphId != 0xffff || i == 0) { if (i < nfo->glyphs->numGlyphs) { @@ -1032,6 +1068,7 @@ bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyph nfo.callbackCalled = false; nfo.flags = flags; nfo.shaperItem = shaperItem; + nfo.styleStrategy = fontDef.styleStrategy; int prevNumGlyphs = *nglyphs; @@ -1061,8 +1098,6 @@ bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyph | kATSLineDisableAllJustification ; - layopts |= kATSLineUseDeviceMetrics; - if (fontDef.styleStrategy & QFont::NoAntialias) layopts |= kATSLineNoAntiAliasing; @@ -1366,14 +1401,22 @@ void QFontEngineMac::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla for (int i = 0; i < glyphs->numGlyphs; ++i) { glyphs->advances_x[i] = QFixed::fromReal(metrics[i].deviceAdvance.x); glyphs->advances_y[i] = QFixed::fromReal(metrics[i].deviceAdvance.y); + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + glyphs->advances_x[i] = glyphs->advances_x[i].ceil(); + glyphs->advances_y[i] = glyphs->advances_y[i].ceil(); + } } } glyph_metrics_t QFontEngineMac::boundingBox(const QGlyphLayout &glyphs) { QFixed w; - for (int i = 0; i < glyphs.numGlyphs; ++i) - w += glyphs.effectiveAdvance(i); + for (int i = 0; i < glyphs.numGlyphs; ++i) { + w += (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? glyphs.effectiveAdvance(i).ceil() + : glyphs.effectiveAdvance(i); + } return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0); } @@ -1398,39 +1441,58 @@ glyph_metrics_t QFontEngineMac::boundingBox(glyph_t glyph) gm.xoff = QFixed::fromReal(metrics.deviceAdvance.x); gm.yoff = QFixed::fromReal(metrics.deviceAdvance.y); + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + gm.x = gm.x.floor(); + gm.y = gm.y.floor(); + gm.xoff = gm.xoff.ceil(); + gm.yoff = gm.yoff.ceil(); + } + return gm; } QFixed QFontEngineMac::ascent() const { - return m_ascent; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? m_ascent.ceil() + : m_ascent; } QFixed QFontEngineMac::descent() const { // subtract a pixel to even out the historical +1 in QFontMetrics::height(). // Fix in Qt 5. - return m_descent - 1; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? m_descent.ceil() - 1 + : m_descent; } QFixed QFontEngineMac::leading() const { - return m_leading; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? m_leading.ceil() + : m_leading; } qreal QFontEngineMac::maxCharWidth() const { - return m_maxCharWidth; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qCeil(m_maxCharWidth) + : m_maxCharWidth; } QFixed QFontEngineMac::xHeight() const { - return m_xHeight; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? m_xHeight.ceil() + : m_xHeight; } QFixed QFontEngineMac::averageCharWidth() const { - return m_averageCharWidth; + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? m_averageCharWidth.ceil() + : m_averageCharWidth; } static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path) diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 13a5704..7f9ae8b 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -328,7 +328,7 @@ int QFontMetrics::height() const { QFontEngine *engine = d->engineForScript(QUnicodeTables::Common); Q_ASSERT(engine != 0); - return qRound(engine->ascent() + engine->descent()) + 1; + return qRound(engine->ascent()) + qRound(engine->descent()) + 1; } /*! @@ -356,7 +356,7 @@ int QFontMetrics::lineSpacing() const { QFontEngine *engine = d->engineForScript(QUnicodeTables::Common); Q_ASSERT(engine != 0); - return qRound(engine->leading() + engine->ascent() + engine->descent()) + 1; + return qRound(engine->leading()) + qRound(engine->ascent()) + qRound(engine->descent()) + 1; } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 1fabf12..d685cd9 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -553,12 +553,14 @@ void QStaticTextPrivate::paintText(const QPointF &pos, QPainter *p) } else { QTextDocument document; document.setDefaultFont(font); + document.setDocumentMargin(0.0); document.setHtml(text); - QRectF rect = maximumSize.isValid() ? QRectF(pos, maximumSize) : QRectF(); + QPointF adjustedPos = pos - QPointF(0, QFontMetricsF(font).ascent()); + QRectF rect = maximumSize.isValid() ? QRectF(adjustedPos, maximumSize) : QRectF(); document.adjustSize(); p->save(); - p->translate(pos); + p->translate(adjustedPos); document.drawContents(p, rect); p->restore(); actualSize = document.size(); diff --git a/src/gui/widgets/qlabel.cpp b/src/gui/widgets/qlabel.cpp index b81f04f..bdbd0b0 100644 --- a/src/gui/widgets/qlabel.cpp +++ b/src/gui/widgets/qlabel.cpp @@ -53,6 +53,7 @@ #include <qurl.h> #include "qlabel_p.h" #include "private/qstylesheetstyle_p.h" +#include <qmath.h> QT_BEGIN_NAMESPACE @@ -661,7 +662,9 @@ QSize QLabelPrivate::sizeForWidth(int w) const } else { control->setTextWidth(-1); } - br = QRect(QPoint(0, 0), control->size().toSize()); + + QSizeF controlSize = control->size(); + br = QRect(QPoint(0, 0), QSize(qCeil(controlSize.width()), qCeil(controlSize.height()))); // restore state control->setTextWidth(oldTextWidth); diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index dd82581..5da1831 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -94,136 +94,207 @@ public: delete [] m_maskData; } - int nextMaskBlank(int pos); - int prevMaskBlank(int pos); + int nextMaskBlank(int pos) + { + int c = findInMask(pos, true, false); + m_separator |= (c != pos); + return (c != -1 ? c : m_maxLength); + } + + int prevMaskBlank(int pos) + { + int c = findInMask(pos, false, false); + m_separator |= (c != pos); + return (c != -1 ? c : 0); + } + + bool isUndoAvailable() const { return !m_readOnly && m_undoState; } + bool isRedoAvailable() const { return !m_readOnly && m_undoState < (int)m_history.size(); } + void clearUndo() { m_history.clear(); m_modifiedState = m_undoState = 0; } - bool isUndoAvailable() const; - bool isRedoAvailable() const; - void clearUndo(); - bool isModified() const; - void setModified(bool modified); + bool isModified() const { return m_modifiedState != m_undoState; } + void setModified(bool modified) { m_modifiedState = modified ? -1 : m_undoState; } - bool allSelected() const; - bool hasSelectedText() const; + bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); } + bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; } - int width() const; - int height() const; - int ascent() const; - qreal naturalTextWidth() const; + int width() const { return qRound(m_textLayout.lineAt(0).width()) + 1; } + int height() const { return qRound(m_textLayout.lineAt(0).height()) + 1; } + int ascent() const { return m_ascent; } + qreal naturalTextWidth() const { return m_textLayout.lineAt(0).naturalTextWidth(); } void setSelection(int start, int length); - QString selectedText() const; - QString textBeforeSelection() const; - QString textAfterSelection() const; + inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); } + QString textBeforeSelection() const { return hasSelectedText() ? m_text.left(m_selstart) : QString(); } + QString textAfterSelection() const { return hasSelectedText() ? m_text.mid(m_selend) : QString(); } - int selectionStart() const; - int selectionEnd() const; - bool inSelection(int x) const; + int selectionStart() const { return hasSelectedText() ? m_selstart : -1; } + int selectionEnd() const { return hasSelectedText() ? m_selend : -1; } + bool inSelection(int x) const + { + if (m_selstart >= m_selend) + return false; + int pos = xToPos(x, QTextLine::CursorOnCharacter); + return pos >= m_selstart && pos < m_selend; + } - void removeSelection(); + void removeSelection() + { + int priorState = m_undoState; + removeSelectedText(); + finishChange(priorState); + } - int start() const; - int end() const; + int start() const { return 0; } + int end() const { return m_text.length(); } #ifndef QT_NO_CLIPBOARD void copy(QClipboard::Mode mode = QClipboard::Clipboard) const; void paste(QClipboard::Mode mode = QClipboard::Clipboard); #endif - int cursor() const; - int preeditCursor() const; + int cursor() const{ return m_cursor; } + int preeditCursor() const { return m_preeditCursor; } + + int cursorWidth() const { return m_cursorWidth; } + void setCursorWidth(int value) { m_cursorWidth = value; } - int cursorWidth() const; - void setCursorWidth(int value); void moveCursor(int pos, bool mark = false); - void cursorForward(bool mark, int steps); - void cursorWordForward(bool mark); - void cursorWordBackward(bool mark); - void home(bool mark); - void end(bool mark); + void cursorForward(bool mark, int steps) + { + int c = m_cursor; + if (steps > 0) { + while (steps--) + c = m_textLayout.nextCursorPosition(c); + } else if (steps < 0) { + while (steps++) + c = m_textLayout.previousCursorPosition(c); + } + moveCursor(c, mark); + } + + void cursorWordForward(bool mark) { moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } + void cursorWordBackward(bool mark) { moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); } + + void home(bool mark) { moveCursor(0, mark); } + void end(bool mark) { moveCursor(text().length(), mark); } int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; QRect cursorRect() const; - qreal cursorToX(int cursor) const; - qreal cursorToX() const; - - bool isReadOnly() const; - void setReadOnly(bool enable); + qreal cursorToX(int cursor) const { return m_textLayout.lineAt(0).cursorToX(cursor); } + qreal cursorToX() const + { + int cursor = m_cursor; + if (m_preeditCursor != -1) + cursor += m_preeditCursor; + return cursorToX(cursor); + } - QString text() const; - void setText(const QString &txt); + bool isReadOnly() const { return m_readOnly; } + void setReadOnly(bool enable) { m_readOnly = enable; } - QString displayText() const; + QString text() const + { + QString res = m_maskData ? stripString(m_text) : m_text; + return (res.isNull() ? QString::fromLatin1("") : res); + } + void setText(const QString &txt) { internalSetText(txt, -1, false); } + QString displayText() const { return m_textLayout.text(); } void backspace(); void del(); - void deselect(); - void selectAll(); + void deselect() { internalDeselect(); finishChange(); } + void selectAll() { m_selstart = m_selend = m_cursor = 0; moveCursor(m_text.length(), true); } + void insert(const QString &); void clear(); - void undo(); - void redo(); + void undo() { internalUndo(); finishChange(-1, true); } + void redo() { internalRedo(); finishChange(); } void selectWordAtPos(int); - uint echoMode() const; - void setEchoMode(uint mode); + uint echoMode() const { return m_echoMode; } + void setEchoMode(uint mode) + { + m_echoMode = mode; + m_passwordEchoEditing = false; + updateDisplayText(); + } - void setMaxLength(int maxLength); - int maxLength() const; + int maxLength() const { return m_maxLength; } + void setMaxLength(int maxLength) + { + if (m_maskData) + return; + m_maxLength = maxLength; + setText(m_text); + } #ifndef QT_NO_VALIDATOR - const QValidator *validator() const; - void setValidator(const QValidator *); + const QValidator *validator() const { return m_validator; } + void setValidator(const QValidator *v) { m_validator = const_cast<QValidator*>(v); } #endif #ifndef QT_NO_COMPLETER - QCompleter *completer() const; - void setCompleter(const QCompleter*); + QCompleter *completer() const { return m_completer; } + /* Note that you must set the widget for the completer seperately */ + void setCompleter(const QCompleter *c) { m_completer = const_cast<QCompleter*>(c); } void complete(int key); #endif - void setCursorPosition(int pos); - int cursorPosition() const; + int cursorPosition() const { return m_cursor; } + void setCursorPosition(int pos) { if (pos <= m_text.length()) moveCursor(qMax(0, pos)); } - bool hasAcceptableInput() const; + bool hasAcceptableInput() const { return hasAcceptableInput(m_text); } bool fixup(); - QString inputMask() const; - void setInputMask(const QString &mask); + QString inputMask() const { return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); } + void setInputMask(const QString &mask) + { + parseInputMask(mask); + if (m_maskData) + moveCursor(nextMaskBlank(0)); + } // input methods #ifndef QT_NO_IM - bool composeMode() const; - void setPreeditArea(int cursor, const QString &text); + bool composeMode() const { return !m_textLayout.preeditAreaText().isEmpty(); } + void setPreeditArea(int cursor, const QString &text) { m_textLayout.setPreeditArea(cursor, text); } #endif - QString preeditAreaText() const; + QString preeditAreaText() const { return m_textLayout.preeditAreaText(); } void updatePasswordEchoEditing(bool editing); - bool passwordEchoEditing() const; + bool passwordEchoEditing() const { return m_passwordEchoEditing; } - QChar passwordCharacter() const; - void setPasswordCharacter(const QChar &character); + QChar passwordCharacter() const { return m_passwordCharacter; } + void setPasswordCharacter(const QChar &character) { m_passwordCharacter = character; updateDisplayText(); } - Qt::LayoutDirection layoutDirection() const; - void setLayoutDirection(Qt::LayoutDirection direction); - void setFont(const QFont &font); + Qt::LayoutDirection layoutDirection() const { return m_layoutDirection; } + void setLayoutDirection(Qt::LayoutDirection direction) + { + if (direction != m_layoutDirection) { + m_layoutDirection = direction; + updateDisplayText(); + } + } + + void setFont(const QFont &font) { m_textLayout.setFont(font); updateDisplayText(); } void processInputMethodEvent(QInputMethodEvent *event); void processMouseEvent(QMouseEvent* ev); void processKeyEvent(QKeyEvent* ev); - int cursorBlinkPeriod() const; + int cursorBlinkPeriod() const { return m_blinkPeriod; } void setCursorBlinkPeriod(int msec); - QString cancelText() const; - void setCancelText(const QString &text); + QString cancelText() const { return m_cancelText; } + void setCancelText(const QString &text) { m_cancelText = text; } - const QPalette &palette() const; - void setPalette(const QPalette &); + const QPalette &palette() const { return m_palette; } + void setPalette(const QPalette &p) { m_palette = p; } enum DrawFlags { DrawText = 0x01, @@ -363,406 +434,6 @@ private Q_SLOTS: }; -inline int QLineControl::nextMaskBlank(int pos) -{ - int c = findInMask(pos, true, false); - m_separator |= (c != pos); - return (c != -1 ? c : m_maxLength); -} - -inline int QLineControl::prevMaskBlank(int pos) -{ - int c = findInMask(pos, false, false); - m_separator |= (c != pos); - return (c != -1 ? c : 0); -} - -inline bool QLineControl::isUndoAvailable() const -{ - return !m_readOnly && m_undoState; -} - -inline bool QLineControl::isRedoAvailable() const -{ - return !m_readOnly && m_undoState < (int)m_history.size(); -} - -inline void QLineControl::clearUndo() -{ - m_history.clear(); - m_modifiedState = m_undoState = 0; -} - -inline bool QLineControl::isModified() const -{ - return m_modifiedState != m_undoState; -} - -inline void QLineControl::setModified(bool modified) -{ - m_modifiedState = modified ? -1 : m_undoState; -} - -inline bool QLineControl::allSelected() const -{ - return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); -} - -inline bool QLineControl::hasSelectedText() const -{ - return !m_text.isEmpty() && m_selend > m_selstart; -} - -inline int QLineControl::width() const -{ - return qRound(m_textLayout.lineAt(0).width()) + 1; -} - -inline qreal QLineControl::naturalTextWidth() const -{ - return m_textLayout.lineAt(0).naturalTextWidth(); -} - -inline int QLineControl::height() const -{ - return qRound(m_textLayout.lineAt(0).height()) + 1; -} - -inline int QLineControl::ascent() const -{ - return m_ascent; -} - -inline QString QLineControl::selectedText() const -{ - if (hasSelectedText()) - return m_text.mid(m_selstart, m_selend - m_selstart); - return QString(); -} - -inline QString QLineControl::textBeforeSelection() const -{ - if (hasSelectedText()) - return m_text.left(m_selstart); - return QString(); -} - -inline QString QLineControl::textAfterSelection() const -{ - if (hasSelectedText()) - return m_text.mid(m_selend); - return QString(); -} - -inline int QLineControl::selectionStart() const -{ - return hasSelectedText() ? m_selstart : -1; -} - -inline int QLineControl::selectionEnd() const -{ - return hasSelectedText() ? m_selend : -1; -} - -inline int QLineControl::start() const -{ - return 0; -} - -inline int QLineControl::end() const -{ - return m_text.length(); -} - -inline void QLineControl::removeSelection() -{ - int priorState = m_undoState; - removeSelectedText(); - finishChange(priorState); -} - -inline bool QLineControl::inSelection(int x) const -{ - if (m_selstart >= m_selend) - return false; - int pos = xToPos(x, QTextLine::CursorOnCharacter); - return pos >= m_selstart && pos < m_selend; -} - -inline int QLineControl::cursor() const -{ - return m_cursor; -} - -inline int QLineControl::preeditCursor() const -{ - return m_preeditCursor; -} - -inline int QLineControl::cursorWidth() const -{ - return m_cursorWidth; -} - -inline void QLineControl::setCursorWidth(int value) -{ - m_cursorWidth = value; -} - -inline void QLineControl::cursorForward(bool mark, int steps) -{ - int c = m_cursor; - if (steps > 0) { - while (steps--) - c = m_textLayout.nextCursorPosition(c); - } else if (steps < 0) { - while (steps++) - c = m_textLayout.previousCursorPosition(c); - } - moveCursor(c, mark); -} - -inline void QLineControl::cursorWordForward(bool mark) -{ - moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); -} - -inline void QLineControl::home(bool mark) -{ - moveCursor(0, mark); -} - -inline void QLineControl::end(bool mark) -{ - moveCursor(text().length(), mark); -} - -inline void QLineControl::cursorWordBackward(bool mark) -{ - moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); -} - -inline qreal QLineControl::cursorToX(int cursor) const -{ - return m_textLayout.lineAt(0).cursorToX(cursor); -} - -inline qreal QLineControl::cursorToX() const -{ - int cursor = m_cursor; - if (m_preeditCursor != -1) - cursor += m_preeditCursor; - return cursorToX(cursor); -} - -inline bool QLineControl::isReadOnly() const -{ - return m_readOnly; -} - -inline void QLineControl::setReadOnly(bool enable) -{ - m_readOnly = enable; -} - -inline QString QLineControl::text() const -{ - QString res = m_maskData ? stripString(m_text) : m_text; - return (res.isNull() ? QString::fromLatin1("") : res); -} - -inline void QLineControl::setText(const QString &txt) -{ - internalSetText(txt, -1, false); -} - -inline QString QLineControl::displayText() const -{ - return m_textLayout.text(); -} - -inline void QLineControl::deselect() -{ - internalDeselect(); - finishChange(); -} - -inline void QLineControl::selectAll() -{ - m_selstart = m_selend = m_cursor = 0; - moveCursor(m_text.length(), true); -} - -inline void QLineControl::undo() -{ - internalUndo(); - finishChange(-1, true); -} - -inline void QLineControl::redo() -{ - internalRedo(); - finishChange(); -} - -inline uint QLineControl::echoMode() const -{ - return m_echoMode; -} - -inline void QLineControl::setEchoMode(uint mode) -{ - m_echoMode = mode; - m_passwordEchoEditing = false; - updateDisplayText(); -} - -inline void QLineControl::setMaxLength(int maxLength) -{ - if (m_maskData) - return; - m_maxLength = maxLength; - setText(m_text); -} - -inline int QLineControl::maxLength() const -{ - return m_maxLength; -} - -#ifndef QT_NO_VALIDATOR -inline const QValidator *QLineControl::validator() const -{ - return m_validator; -} - -inline void QLineControl::setValidator(const QValidator *v) -{ - m_validator = const_cast<QValidator*>(v); -} -#endif - -#ifndef QT_NO_COMPLETER -inline QCompleter *QLineControl::completer() const -{ - return m_completer; -} - -/* Note that you must set the widget for the completer seperately */ -inline void QLineControl::setCompleter(const QCompleter* c) -{ - m_completer = const_cast<QCompleter*>(c); -} -#endif - -inline void QLineControl::setCursorPosition(int pos) -{ - if (pos < 0) - pos = 0; - if (pos <= m_text.length()) - moveCursor(pos); -} - -inline int QLineControl::cursorPosition() const -{ - return m_cursor; -} - -inline bool QLineControl::hasAcceptableInput() const -{ - return hasAcceptableInput(m_text); -} - -inline QString QLineControl::inputMask() const -{ - return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); -} - -inline void QLineControl::setInputMask(const QString &mask) -{ - parseInputMask(mask); - if (m_maskData) - moveCursor(nextMaskBlank(0)); -} - -// input methods -#ifndef QT_NO_IM -inline bool QLineControl::composeMode() const -{ - return !m_textLayout.preeditAreaText().isEmpty(); -} - -inline void QLineControl::setPreeditArea(int cursor, const QString &text) -{ - m_textLayout.setPreeditArea(cursor, text); -} -#endif - -inline QString QLineControl::preeditAreaText() const -{ - return m_textLayout.preeditAreaText(); -} - -inline bool QLineControl::passwordEchoEditing() const -{ - return m_passwordEchoEditing; -} - -inline QChar QLineControl::passwordCharacter() const -{ - return m_passwordCharacter; -} - -inline void QLineControl::setPasswordCharacter(const QChar &character) -{ - m_passwordCharacter = character; - updateDisplayText(); -} - -inline Qt::LayoutDirection QLineControl::layoutDirection() const -{ - return m_layoutDirection; -} - -inline void QLineControl::setLayoutDirection(Qt::LayoutDirection direction) -{ - if (direction != m_layoutDirection) { - m_layoutDirection = direction; - updateDisplayText(); - } -} - -inline void QLineControl::setFont(const QFont &font) -{ - m_textLayout.setFont(font); - updateDisplayText(); -} - -inline int QLineControl::cursorBlinkPeriod() const -{ - return m_blinkPeriod; -} - -inline QString QLineControl::cancelText() const -{ - return m_cancelText; -} - -inline void QLineControl::setCancelText(const QString &text) -{ - m_cancelText = text; -} - -inline const QPalette & QLineControl::palette() const -{ - return m_palette; -} - -inline void QLineControl::setPalette(const QPalette &p) -{ - m_palette = p; -} - QT_END_NAMESPACE QT_END_HEADER |