QSpanData: use isAffine() instead of rolling your own test
[profile/ivi/qtbase.git] / src / gui / painting / qpaintengine_raster.cpp
index e9a3b7a..0e9129f 100644 (file)
@@ -1,38 +1,38 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the QtGui module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
 ** GNU Lesser General Public License Usage
-** 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.
+** 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
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
 **
 **
 ** $QT_END_LICENSE$
 #include <qbitmap.h>
 #include <qmath.h>
 
-#if defined (Q_WS_X11)
-#  include <private/qfontengine_ft_p.h>
-#endif
-
 //   #include <private/qdatabuffer_p.h>
 //   #include <private/qpainter_p.h>
 #include <private/qmath_p.h>
 //   #include "qbezier_p.h"
 #include "qoutlinemapper_p.h"
 
-#if defined(Q_OS_WIN)
-#  include <qt_windows.h>
+#include <limits.h>
+
+#ifdef Q_OS_WIN
 #  include <qvarlengtharray.h>
 #  include <private/qfontengine_p.h>
-#  if defined(Q_OS_WINCE)
-#    include "qguifunctions_wince.h"
+#  include <qt_windows.h>
+#ifdef Q_OS_WIN64
+#    include <malloc.h>
 #  endif
-#elif defined(Q_WS_MAC)
-#  include <private/qt_mac_p.h>
-#  include <private/qpixmap_mac_p.h>
-#  include <private/qpaintengine_mac_p.h>
-#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
-#  include <private/qfontengine_s60_p.h>
-#elif defined(Q_WS_QPA)
-#  include <private/qfontengine_ft_p.h>
 #endif
 
-#if defined(Q_OS_WIN64)
-#  include <malloc.h>
-#endif
-#include <limits.h>
-
 QT_BEGIN_NAMESPACE
 
+class QRectVectorPath : public QVectorPath {
+public:
+    inline void set(const QRect &r) {
+        qreal left = r.x();
+        qreal right = r.x() + r.width();
+        qreal top = r.y();
+        qreal bottom = r.y() + r.height();
+        pts[0] = left;
+        pts[1] = top;
+        pts[2] = right;
+        pts[3] = top;
+        pts[4] = right;
+        pts[5] = bottom;
+        pts[6] = left;
+        pts[7] = bottom;
+    }
+
+    inline void set(const QRectF &r) {
+        qreal left = r.x();
+        qreal right = r.x() + r.width();
+        qreal top = r.y();
+        qreal bottom = r.y() + r.height();
+        pts[0] = left;
+        pts[1] = top;
+        pts[2] = right;
+        pts[3] = top;
+        pts[4] = right;
+        pts[5] = bottom;
+        pts[6] = left;
+        pts[7] = bottom;
+    }
+    inline QRectVectorPath(const QRect &r)
+        : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+    {
+        set(r);
+    }
+    inline QRectVectorPath(const QRectF &r)
+        : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+    {
+        set(r);
+    }
+    inline QRectVectorPath()
+        : QVectorPath(pts, 4, 0, QVectorPath::RectangleHint | QVectorPath::ImplicitClose)
+    { }
+
+    qreal pts[8];
+};
+
 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
 
 #define qreal_to_fixed_26_6(f) (int(f * 64))
@@ -118,6 +151,8 @@ void dumpClip(int width, int height, const QClipData *clip);
 // 4 pixels.
 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
 
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
 #ifdef Q_OS_WIN
 
 static inline bool winClearTypeFontsEnabled()
@@ -131,6 +166,9 @@ static inline bool winClearTypeFontsEnabled()
     return result == FE_FONTSMOOTHINGCLEARTYPE;
 }
 
+/*!
+    \internal
+ */
 bool QRasterPaintEngine::clearTypeFontsEnabled()
 {
     static const bool result = winClearTypeFontsEnabled();
@@ -139,9 +177,6 @@ bool QRasterPaintEngine::clearTypeFontsEnabled()
 
 #endif // Q_OS_WIN
 
-#ifdef Q_WS_MAC
-extern bool qt_applefontsmoothing_enabled;
-#endif
 
 
 /********************************************************************************
@@ -150,7 +185,6 @@ extern bool qt_applefontsmoothing_enabled;
 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
 static void qt_span_clip(int count, const QSpan *spans, void *userData);
-static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
 
 struct ClipData
 {
@@ -165,6 +199,10 @@ enum LineDrawMode {
     LineDrawIncludeLastPixel
 };
 
+static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
+                                   ProcessSpans pen_func, ProcessSpans brush_func,
+                                   QSpanData *pen_data, QSpanData *brush_data);
+
 struct QRasterFloatPoint {
     qreal x;
     qreal y;
@@ -432,8 +470,8 @@ bool QRasterPaintEngine::begin(QPaintDevice *device)
 
     if (device->devType() == QInternal::Pixmap) {
         QPixmap *pixmap = static_cast<QPixmap *>(device);
-        QPixmapData *pd = pixmap->pixmapData();
-        if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
+        QPlatformPixmap *pd = pixmap->handle();
+        if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass)
             d->device = pd->buffer();
     } else {
         d->device = device;
@@ -479,16 +517,10 @@ bool QRasterPaintEngine::begin(QPaintDevice *device)
     }
 #endif
 
-#if defined(Q_OS_WIN)
-    d->isPlain45DegreeRotation = true;
-#endif
-
     if (d->mono_surface)
         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
 #if defined(Q_OS_WIN)
     else if (clearTypeFontsEnabled())
-#elif defined (Q_WS_MAC)
-    else if (qt_applefontsmoothing_enabled)
 #else
     else if (false)
 #endif
@@ -586,33 +618,6 @@ void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
 
     ensureOutlineMapper();
-
-#ifdef Q_OS_WIN
-    Q_D(QRasterPaintEngine);
-    d->isPlain45DegreeRotation = false;
-    if (txop >= QTransform::TxRotate) {
-        d->isPlain45DegreeRotation =
-            (qFuzzyIsNull(matrix.m11())
-             && qFuzzyIsNull(matrix.m12() - qreal(1))
-             && qFuzzyIsNull(matrix.m21() + qreal(1))
-             && qFuzzyIsNull(matrix.m22())
-                )
-            ||
-            (qFuzzyIsNull(matrix.m11() + qreal(1))
-             && qFuzzyIsNull(matrix.m12())
-             && qFuzzyIsNull(matrix.m21())
-             && qFuzzyIsNull(matrix.m22() + qreal(1))
-                )
-            ||
-            (qFuzzyIsNull(matrix.m11())
-             && qFuzzyIsNull(matrix.m12() + qreal(1))
-             && qFuzzyIsNull(matrix.m21() - qreal(1))
-             && qFuzzyIsNull(matrix.m22())
-                )
-            ;
-    }
-#endif
-
 }
 
 
@@ -639,6 +644,7 @@ QRasterPaintEngineState::QRasterPaintEngineState()
     flags.fast_pen = true;
     flags.antialiased = false;
     flags.bilinear = false;
+    flags.legacy_rounding = false;
     flags.fast_text = true;
     flags.int_xform = true;
     flags.tx_noshear = true;
@@ -765,7 +771,7 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
     } else if (pen_style != Qt::NoPen) {
         if (!d->dashStroker)
             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
-        if (pen.isCosmetic()) {
+        if (qt_pen_is_cosmetic(pen, s->renderHints)) {
             d->dashStroker->setClipRect(d->deviceRect);
         } else {
             // ### I've seen this inverted devrect multiple places now...
@@ -779,11 +785,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
         s->stroker = 0;
     }
 
-    ensureState(); // needed because of tx_noshear...
+    ensureRasterState(); // needed because of tx_noshear...
+    bool cosmetic = qt_pen_is_cosmetic(pen, s->renderHints);
     s->flags.fast_pen = pen_style > Qt::NoPen
             && s->penData.blend
-            && ((pen.isCosmetic() && penWidth <= 1)
-                || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
+            && ((cosmetic && penWidth <= 1)
+                || (!cosmetic && s->flags.tx_noshear && penWidth * s->txscale <= 1));
 
     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
 
@@ -847,7 +854,7 @@ void QRasterPaintEngine::updateOutlineMapper()
     d->outlineMapper->setMatrix(state()->matrix);
 }
 
-void QRasterPaintEngine::updateState()
+void QRasterPaintEngine::updateRasterState()
 {
     QRasterPaintEngineState *s = state();
 
@@ -922,6 +929,7 @@ void QRasterPaintEngine::renderHintsChanged()
 
     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
+    s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
 
     if (was_aa != s->flags.antialiased)
         s->strokeFlags |= DirtyHints;
@@ -1064,9 +1072,11 @@ void QRasterPaintEnginePrivate::systemStateChanged()
     exDeviceRect = deviceRect;
 
     Q_Q(QRasterPaintEngine);
-    q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
-    q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
-    q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
+    if (q->state()) {
+        q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
+        q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
+        q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
+    }
 }
 
 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
@@ -1182,8 +1192,7 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
     const QPainterPath::ElementType *types = path.elements();
 
     // There are some cases that are not supported by clip(QRect)
-    if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
-                                || s->clip->hasRectClip || s->clip->hasRegionClip)) {
+    if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
         if (s->matrix.type() <= QTransform::TxScale
             && ((path.shape() == QVectorPath::RectangleHint)
                 || (isRect(points, path.elementCount())
@@ -1226,18 +1235,6 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
 
         newClip->fixup();
 
-        if (op == Qt::UniteClip) {
-            // merge clips
-            QClipData *result = new QClipData(d->rasterBuffer->height());
-            QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
-            qt_merge_clip(current, newClip, result);
-            result->fixup();
-            delete newClip;
-            if (!s->clip)
-                delete current;
-            newClip = result;
-        }
-
         if (s->flags.has_clip_ownership)
             delete s->clip;
 
@@ -1263,7 +1260,7 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
     if (op == Qt::NoClip) {
         qrasterpaintengine_state_setNoClip(s);
 
-    } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
+    } else if (s->matrix.type() > QTransform::TxScale) {
         QPaintEngineEx::clip(rect, op);
         return;
 
@@ -1348,7 +1345,6 @@ void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
     if (op == Qt::NoClip) {
         qrasterpaintengine_state_setNoClip(s);
     } else if (s->matrix.type() > QTransform::TxScale
-               || op == Qt::UniteClip
                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
         QPaintEngineEx::clip(region, op);
@@ -1381,6 +1377,13 @@ void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
 }
 
 /*!
+ \fn const QClipData *QRasterPaintEngine::clipData() const
+
+ \internal
+*/
+
+
+/*!
     \internal
 */
 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
@@ -1494,7 +1497,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
 #endif
     Q_D(QRasterPaintEngine);
-    ensureState();
+    ensureRasterState();
     QRasterPaintEngineState *s = state();
 
     // Fill
@@ -1526,6 +1529,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
         QRectVectorPath path;
         if (s->flags.fast_pen) {
             QCosmeticStroker stroker(s, d->deviceRect);
+            stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
             for (int i = 0; i < rectCount; ++i) {
                 path.set(rects[i]);
                 stroker.drawPath(path);
@@ -1549,7 +1553,7 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
 #endif
 #ifdef QT_FAST_SPANS
     Q_D(QRasterPaintEngine);
-    ensureState();
+    ensureRasterState();
     QRasterPaintEngineState *s = state();
 
 
@@ -1572,6 +1576,7 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
             QRectVectorPath path;
             if (s->flags.fast_pen) {
                 QCosmeticStroker stroker(s, d->deviceRect);
+                stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
                 for (int i = 0; i < rectCount; ++i) {
                     path.set(rects[i]);
                     stroker.drawPath(path);
@@ -1605,9 +1610,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
 
     if (s->flags.fast_pen) {
         QCosmeticStroker stroker(s, d->deviceRect);
+        stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
         stroker.drawPath(path);
     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
-        qreal width = s->lastPen.isCosmetic()
+        qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints)
                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
                       : qpen_widthf(s->lastPen) * s->txscale;
         int dashIndex = 0;
@@ -1660,12 +1666,16 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
         QPaintEngineEx::stroke(path, pen);
 }
 
-static inline QRect toNormalizedFillRect(const QRectF &rect)
+QRect QRasterPaintEngine::toNormalizedFillRect(const QRectF &rect)
 {
-    int x1 = qRound(rect.x());
-    int y1 = qRound(rect.y());
-    int x2 = qRound(rect.right());
-    int y2 = qRound(rect.bottom());
+    QRasterPaintEngineState *s = state();
+
+    qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
+
+    int x1 = qRound(rect.x() + delta);
+    int y1 = qRound(rect.y() + delta);
+    int x2 = qRound(rect.right() + delta);
+    int y2 = qRound(rect.bottom() + delta);
 
     if (x2 < x1)
         qSwap(x1, x2);
@@ -1705,7 +1715,7 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
             return;
         }
-        ensureState();
+        ensureRasterState();
         if (s->flags.tx_noshear) {
             d->initializeRasterizer(&s->brushData);
             // ### Is normalizing really necessary here?
@@ -1762,7 +1772,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
             return;
         }
     }
-    ensureState();
+    ensureRasterState();
     if (s->flags.tx_noshear) {
         d->initializeRasterizer(data);
         QRectF nr = r.normalized();
@@ -1934,9 +1944,8 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
     if (mode != PolylineMode) {
         // Do the fill...
         ensureBrush();
-        if (s->brushData.blend) {
+        if (s->brushData.blend)
             fillPolygon(points, pointCount, mode);
-        }
     }
 
     // Do the outline...
@@ -1944,6 +1953,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
         if (s->flags.fast_pen) {
             QCosmeticStroker stroker(s, d->deviceRect);
+            stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
             stroker.drawPath(vp);
         } else {
             QPaintEngineEx::stroke(vp, s->lastPen);
@@ -2008,6 +2018,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
 
         if (s->flags.fast_pen) {
             QCosmeticStroker stroker(s, d->deviceRect);
+            stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
             stroker.drawPath(vp);
         } else {
             QPaintEngineEx::stroke(vp, s->lastPen);
@@ -2024,9 +2035,9 @@ void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
 #endif
 
-    QPixmapData *pd = pixmap.pixmapData();
-    if (pd->classId() == QPixmapData::RasterClass) {
-        const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
+    QPlatformPixmap *pd = pixmap.handle();
+    if (pd->classId() == QPlatformPixmap::RasterClass) {
+        const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
         if (image.depth() == 1) {
             Q_D(QRasterPaintEngine);
             QRasterPaintEngineState *s = state();
@@ -2065,9 +2076,9 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons
     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
 #endif
 
-    QPixmapData* pd = pixmap.pixmapData();
-    if (pd->classId() == QPixmapData::RasterClass) {
-        const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
+    QPlatformPixmap* pd = pixmap.handle();
+    if (pd->classId() == QPlatformPixmap::RasterClass) {
+        const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
         if (image.depth() == 1) {
             Q_D(QRasterPaintEngine);
             QRasterPaintEngineState *s = state();
@@ -2105,17 +2116,6 @@ void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, cons
     }
 }
 
-// assumes that rect has positive width and height
-static inline const QRect toRect_normalized(const QRectF &rect)
-{
-    const int x = qRound(rect.x());
-    const int y = qRound(rect.y());
-    const int w = int(rect.width() + qreal(0.5));
-    const int h = int(rect.height() + qreal(0.5));
-
-    return QRect(x, y, w, h);
-}
-
 static inline int fast_ceil_positive(const qreal &v)
 {
     const int iv = int(v);
@@ -2145,9 +2145,10 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
 
     Q_D(QRasterPaintEngine);
     QRasterPaintEngineState *s = state();
+    qreal scale = img.devicePixelRatio();
 
-    if (s->matrix.type() > QTransform::TxTranslate) {
-        drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
+    if (scale > 1.0 ||  s->matrix.type() > QTransform::TxTranslate) {
+        drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
                   img,
                   QRectF(0, 0, img.width(), img.height()));
     } else {
@@ -2244,8 +2245,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
     int sr_b = qCeil(sr.bottom()) - 1;
 
     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
+        // as fillRect will apply the aliased coordinate delta we need to
+        // subtract it here as we don't use it for image drawing
         QTransform old = s->matrix;
 
+        if (s->flags.legacy_rounding)
+            s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
+
         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
         QRgb color = img.pixel(sr_l, sr_t);
         switch (img.format()) {
@@ -2346,6 +2352,22 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
                     return;
                 }
             } else {
+                // Test for optimized high-dpi case: 2x source on 2x target. (Could be generalized to nX.)
+                bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
+                bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
+                if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
+                    SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
+                    if (func) {
+                        QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
+                        if (!clip) {
+                            d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
+                            return;
+                        } else if (clip->hasRectClip) {
+                            d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
+                            return;
+                        }
+                    }
+                }
                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
                 if (func && (!clip || clip->hasRectClip)) {
                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
@@ -2383,14 +2405,17 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
         }
 
 #ifdef QT_FAST_SPANS
-        ensureState();
+        ensureRasterState();
         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
             d->initializeRasterizer(&d->image_filler_xform);
             d->rasterizer->setAntialiased(s->flags.antialiased);
+            d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
+
+            const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF();
 
             const QRectF &rect = r.normalized();
-            const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
-            const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
+            const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
+            const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
 
             if (s->flags.tx_noshear)
                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
@@ -2399,12 +2424,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
             return;
         }
 #endif
+        const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
         QPainterPath path;
         path.addRect(r);
         QTransform m = s->matrix;
         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
                                m.m21(), m.m22(), m.m23(),
-                               m.m31(), m.m32(), m.m33());
+                               m.m31() - offs, m.m32() - offs, m.m33());
         fillPath(path, &d->image_filler_xform);
         s->matrix = m;
     } else {
@@ -2454,9 +2480,9 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
 
     QImage image;
 
-    QPixmapData *pd = pixmap.pixmapData();
-    if (pd->classId() == QPixmapData::RasterClass) {
-        image = static_cast<QRasterPixmapData *>(pd)->image;
+    QPlatformPixmap *pd = pixmap.handle();
+    if (pd->classId() == QPlatformPixmap::RasterClass) {
+        image = static_cast<QRasterPlatformPixmap *>(pd)->image;
     } else {
         image = pixmap.toImage();
     }
@@ -2475,10 +2501,11 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
 
 #ifdef QT_FAST_SPANS
-        ensureState();
+        ensureRasterState();
         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
             d->initializeRasterizer(&d->image_filler_xform);
             d->rasterizer->setAntialiased(s->flags.antialiased);
+            d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
 
             const QRectF &rect = r.normalized();
             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
@@ -2517,6 +2544,15 @@ static inline bool monoVal(const uchar* s, int x)
 
 /*!
     \internal
+ */
+QRasterBuffer *QRasterPaintEngine::rasterBuffer()
+{
+    Q_D(QRasterPaintEngine);
+    return d->rasterBuffer.data();
+}
+
+/*!
+    \internal
 */
 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
 {
@@ -2741,97 +2777,42 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
         blend(current, spans, &s->penData);
 }
 
+/*!
+    \internal
+*/
 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
                                           const QFixedPoint *positions, QFontEngine *fontEngine)
 {
     Q_D(QRasterPaintEngine);
     QRasterPaintEngineState *s = state();
 
-#if !defined(QT_NO_FREETYPE)
-    if (fontEngine->type() == QFontEngine::Freetype) {
-        QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
-        QFontEngineFT::GlyphFormat neededFormat =
+    if (fontEngine->hasInternalCaching()) {
+        QFontEngine::GlyphFormat neededFormat =
             painter()->device()->devType() == QInternal::Widget
-            ? fe->defaultGlyphFormat()
-            : QFontEngineFT::Format_A8;
-
-        if (d_func()->mono_surface
-            || fe->isBitmapFont() // alphaPenBlt can handle mono, too
-            )
-            neededFormat = QFontEngineFT::Format_Mono;
+            ? QFontEngine::Format_None
+            : QFontEngine::Format_A8;
 
-        if (neededFormat == QFontEngineFT::Format_None)
-            neededFormat = QFontEngineFT::Format_A8;
-
-        QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
-        if (s->matrix.type() >= QTransform::TxScale) {
-            if (s->matrix.isAffine())
-                gset = fe->loadTransformedGlyphSet(s->matrix);
-            else
-                gset = 0;
-        }
-
-        if (!gset || gset->outline_drawing
-            || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
-            return false;
-
-        FT_Face lockedFace = 0;
-
-        int depth;
-        switch (neededFormat) {
-        case QFontEngineFT::Format_Mono:
-            depth = 1;
-            break;
-        case QFontEngineFT::Format_A8:
-            depth = 8;
-            break;
-        case QFontEngineFT::Format_A32:
-            depth = 32;
-            break;
-        default:
-            Q_ASSERT(false);
-            depth = 0;
-        };
+        if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
+            neededFormat = QFontEngine::Format_Mono;
 
         for (int i = 0; i < numGlyphs; i++) {
-            QFixed spp = fe->subPixelPositionForX(positions[i].x);
-            QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
-
-            if (!glyph || glyph->format != neededFormat) {
-                if (!lockedFace)
-                    lockedFace = fe->lockFace();
-                glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
-            }
+            QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
 
-            if (!glyph || !glyph->data)
+            QPoint offset;
+            QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
+                                                                  &offset);
+            if (alphaMap == 0 || alphaMap->isNull())
                 continue;
 
-            int pitch;
-            switch (neededFormat) {
-            case QFontEngineFT::Format_Mono:
-                pitch = ((glyph->width + 31) & ~31) >> 3;
-                break;
-            case QFontEngineFT::Format_A8:
-                pitch = (glyph->width + 3) & ~3;
-                break;
-            case QFontEngineFT::Format_A32:
-                pitch = glyph->width * 4;
-                break;
-            default:
-                Q_ASSERT(false);
-                pitch = 0;
-            };
-
-            alphaPenBlt(glyph->data, pitch, depth,
-                        qFloor(positions[i].x) + glyph->x,
-                        qFloor(positions[i].y) - glyph->y,
-                        glyph->width, glyph->height);
+            alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
+                        qFloor(positions[i].x) + offset.x(),
+                        qRound(positions[i].y) + offset.y(),
+                        alphaMap->width(), alphaMap->height());
+
+            fontEngine->unlockAlphaMapForGlyph();
         }
-        if (lockedFace)
-            fe->unlockFace();
-    } else
-#endif
-    {
+
+    } else {
         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
 
         QImageTextureGlyphCache *cache =
@@ -2855,18 +2836,18 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
         else if (depth == 1)
             rightShift = 3; // divide by 8
 
-        int margin = cache->glyphMargin();
+        int margin = fontEngine->glyphMargin(glyphType);
         const uchar *bits = image.bits();
         for (int i=0; i<numGlyphs; ++i) {
 
-            QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
+            QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
             if (c.isNull())
                 continue;
 
             int x = qFloor(positions[i].x) + c.baseLineX - margin;
-            int y = qFloor(positions[i].y) - c.baseLineY - margin;
+            int y = qRound(positions[i].y) - c.baseLineY - margin;
 
             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
             //        c.x, c.y,
@@ -2882,44 +2863,6 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
     return true;
 }
 
-#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
-void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
-{
-    Q_D(QRasterPaintEngine);
-    QRasterPaintEngineState *s = state();
-
-    QFontEngine *fontEngine = ti.fontEngine;
-    if (fontEngine->type() != QFontEngine::S60FontEngine) {
-        QPaintEngineEx::drawTextItem(p, ti);
-        return;
-    }
-
-    QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
-
-    QVarLengthArray<QFixedPoint> positions;
-    QVarLengthArray<glyph_t> glyphs;
-    QTransform matrix = s->matrix;
-    matrix.translate(p.x(), p.y());
-    if (matrix.type() == QTransform::TxScale)
-        fe->setFontScale(matrix.m11());
-    ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
-    for (int i=0; i<glyphs.size(); ++i) {
-        TOpenFontCharMetrics tmetrics;
-        const TUint8 *glyphBitmapBytes;
-        TSize glyphBitmapSize;
-        fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
-        const int x = qFloor(positions[i].x + tmetrics.HorizBearingX());
-        const int y = qFloor(positions[i].y - tmetrics.HorizBearingY());
-        alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
-    }
-
-    if (matrix.type() == QTransform::TxScale)
-        fe->setFontScale(1.0);
-
-    return;
-}
-#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
 
 /*!
  * Returns true if the rectangle is completely within the current clip
@@ -3010,18 +2953,81 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
 }
 
+inline ProcessSpans
+QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
+                                      const QSpanData *data) const
+{
+    Q_Q(const QRasterPaintEngine);
+    const QRasterPaintEngineState *s = q->state();
+
+    if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
+        return data->blend;
+    const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
+    return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
+}
+
+static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
+                                         glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
+{
+    QFixed clipLeft = QFixed::fromReal(clip.left());
+    QFixed clipRight = QFixed::fromReal(clip.right());
+    QFixed clipTop = QFixed::fromReal(clip.top());
+    QFixed clipBottom = QFixed::fromReal(clip.bottom());
+
+    int first = 0;
+    while (first < numGlyphs) {
+        glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
+        QFixed left = metrics.x + positions[first].x;
+        QFixed top = metrics.y + positions[first].y;
+        QFixed right = left + metrics.width;
+        QFixed bottom = top + metrics.height;
+        if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+            break;
+        ++first;
+    }
+    int last = numGlyphs - 1;
+    while (last > first) {
+        glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
+        QFixed left = metrics.x + positions[last].x;
+        QFixed top = metrics.y + positions[last].y;
+        QFixed right = left + metrics.width;
+        QFixed bottom = top + metrics.height;
+        if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+            break;
+        --last;
+    }
+    return QPair<int, int>(first, last + 1);
+}
+
 /*!
    \reimp
 */
 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
 {
+    if (textItem->numGlyphs == 0)
+        return;
+
     ensurePen();
-    ensureState();
+    ensureRasterState();
 
     QFontEngine *fontEngine = textItem->fontEngine();
     if (!supportsTransformations(fontEngine)) {
         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
                          fontEngine);
+    } else if (state()->matrix.type() < QTransform::TxProject) {
+        bool invertible;
+        QTransform invMat = state()->matrix.inverted(&invertible);
+        if (!invertible)
+            return;
+
+        QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+                                                  textItem->fontEngine(), textItem->glyphs,
+                                                  textItem->glyphPositions, textItem->numGlyphs);
+        QStaticTextItem copy = *textItem;
+        copy.glyphs += range.first;
+        copy.glyphPositions += range.first;
+        copy.numGlyphs = range.second - range.first;
+        QPaintEngineEx::drawStaticTextItem(&copy);
     } else {
         QPaintEngineEx::drawStaticTextItem(textItem);
     }
@@ -3033,7 +3039,6 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
 {
     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
-    QRasterPaintEngineState *s = state();
 
 #ifdef QT_DEBUG_DRAW
     Q_D(QRasterPaintEngine);
@@ -3042,88 +3047,51 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
            d->glyphCacheType);
 #endif
 
+    if (ti.glyphs.numGlyphs == 0)
+        return;
     ensurePen();
-    ensureState();
+    ensureRasterState();
 
-#if defined (Q_OS_WIN) || defined(Q_WS_MAC)
+    QRasterPaintEngineState *s = state();
+    QTransform matrix = s->matrix;
 
     if (!supportsTransformations(ti.fontEngine)) {
         QVarLengthArray<QFixedPoint> positions;
         QVarLengthArray<glyph_t> glyphs;
 
-        QTransform matrix = s->matrix;
         matrix.translate(p.x(), p.y());
-
         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
 
         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
-        return;
-    }
-
-#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_OS_WIN || Q_WS_MAC
-    if (s->matrix.type() <= QTransform::TxTranslate
-        || (s->matrix.type() == QTransform::TxScale
-                && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
-        drawGlyphsS60(p, ti);
-        return;
-    }
-#else // Q_OS_WIN || Q_WS_MAC
-
-    QFontEngine *fontEngine = ti.fontEngine;
-
-#ifdef Q_WS_QPA
-    if (s->matrix.type() < QTransform::TxScale) {
+    } else if (matrix.type() < QTransform::TxProject) {
+        bool invertible;
+        QTransform invMat = matrix.inverted(&invertible);
+        if (!invertible)
+            return;
 
         QVarLengthArray<QFixedPoint> positions;
         QVarLengthArray<glyph_t> glyphs;
-        QTransform matrix = state()->transform();
 
-        qreal _x = qFloor(p.x());
-        qreal _y = qFloor(p.y());
-        matrix.translate(_x, _y);
+        ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
+                                         ti.flags, glyphs, positions);
+        QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+                                                  ti.fontEngine, glyphs.data(), positions.data(),
+                                                  glyphs.size());
 
-        fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-        if (glyphs.size() == 0)
+        if (range.first >= range.second)
             return;
 
-        for(int i = 0; i < glyphs.size(); i++) {
-            QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
-            glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
-            alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
-                                         qRound(positions[i].x + metrics.x),
-                                         qRound(positions[i].y + metrics.y),
-                                         img.width(), img.height());
-        }
-        return;
-    }
-#endif //Q_WS_QPA
-
-#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
-
-    if (fontEngine->type() != QFontEngine::Freetype) {
+        QStaticTextItem staticTextItem;
+        staticTextItem.color = s->pen.color();
+        staticTextItem.font = s->font;
+        staticTextItem.setFontEngine(ti.fontEngine);
+        staticTextItem.numGlyphs = range.second - range.first;
+        staticTextItem.glyphs = glyphs.data() + range.first;
+        staticTextItem.glyphPositions = positions.data() + range.first;
+        QPaintEngineEx::drawStaticTextItem(&staticTextItem);
+    } else {
         QPaintEngineEx::drawTextItem(p, ti);
-        return;
     }
-
-    QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
-
-    QTransform matrix = s->matrix;
-    matrix.translate(p.x(), p.y());
-
-    QVarLengthArray<QFixedPoint> positions;
-    QVarLengthArray<glyph_t> glyphs;
-    fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-    if (glyphs.size() == 0)
-        return;
-
-    if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
-        QPaintEngine::drawTextItem(p, ti);
-
-    return;
-#endif
-#endif
-
-    QPaintEngineEx::drawTextItem(p, ti);
 }
 
 /*!
@@ -3144,6 +3112,7 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
     }
 
     QCosmeticStroker stroker(s, d->deviceRect);
+    stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
     stroker.drawPoints(points, pointCount);
 }
 
@@ -3163,6 +3132,7 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
     }
 
     QCosmeticStroker stroker(s, d->deviceRect);
+    stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
     stroker.drawPoints(points, pointCount);
 }
 
@@ -3183,6 +3153,7 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
 
     if (s->flags.fast_pen) {
         QCosmeticStroker stroker(s, d->deviceRect);
+        stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
         for (int i=0; i<lineCount; ++i) {
             const QLine &l = lines[i];
             stroker.drawLine(l.p1(), l.p2());
@@ -3254,6 +3225,7 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
         return;
     if (s->flags.fast_pen) {
         QCosmeticStroker stroker(s, d->deviceRect);
+        stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
         for (int i=0; i<lineCount; ++i) {
             QLineF line = lines[i];
             stroker.drawLine(line.p1(), line.p2());
@@ -3269,28 +3241,33 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
 */
 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
 {
-    QPaintEngineEx::drawEllipse(rect);
-}
-
-/*!
-    \internal
-*/
-#ifdef Q_WS_MAC
-void QRasterPaintEngine::setCGContext(CGContextRef ctx)
-{
     Q_D(QRasterPaintEngine);
-    d->cgContext = ctx;
-}
+    QRasterPaintEngineState *s = state();
 
-/*!
-    \internal
-*/
-CGContextRef QRasterPaintEngine::getCGContext() const
-{
-    Q_D(const QRasterPaintEngine);
-    return d->cgContext;
+    ensurePen();
+    if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
+           || (qpen_style(s->lastPen) == Qt::NoPen))
+        && !s->flags.antialiased
+        && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
+        && !rect.isEmpty()
+        && s->matrix.type() <= QTransform::TxScale) // no shear
+    {
+        ensureBrush();
+        const QRectF r = s->matrix.mapRect(rect);
+        ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
+        ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
+        const QRect brect = QRect(int(r.x()), int(r.y()),
+                                  int_dim(r.x(), r.width()),
+                                  int_dim(r.y(), r.height()));
+        if (brect == r) {
+            drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
+                                   &s->penData, &s->brushData);
+            return;
+        }
+    }
+    QPaintEngineEx::drawEllipse(rect);
 }
-#endif
+
 
 #ifdef Q_OS_WIN
 /*!
@@ -3319,35 +3296,24 @@ void QRasterPaintEngine::releaseDC(HDC) const
 
 #endif
 
-bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
+/*!
+    \internal
+*/
+bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const
 {
     const QTransform &m = state()->matrix;
-#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
-    QFontEngine::Type fontEngineType = fontEngine->type();
-    if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
-        || (m.type() <= QTransform::TxTranslate
-            && (fontEngineType == QFontEngine::TestFontEngine
-                || fontEngineType == QFontEngine::Box))) {
-            return true;
-    }
-#endif
-    return supportsTransformations(fontEngine->fontDef.pixelSize, m);
+    return supportsTransformations(fontEngine, m);
 }
 
-bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
+/*!
+    \internal
+*/
+bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const
 {
-#if defined(Q_WS_MAC)
-    // Mac font engines don't support scaling and rotation
-    if (m.type() > QTransform::TxTranslate)
-#else
-    if (m.type() >= QTransform::TxProject)
-#endif
-        return true;
-
-    if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
+    if (fontEngine->supportsTransformations(m))
         return true;
 
-    return false;
+    return !shouldDrawCachedGlyphs(fontEngine, m);
 }
 
 /*!
@@ -3397,7 +3363,7 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp
                     spans[n].y = y;
                     spans[n].coverage = 255;
                     int len = 1;
-                    while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
+                    while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
                         ++src_x;
                         ++len;
                     }
@@ -3423,7 +3389,7 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp
                     spans[n].y = y;
                     spans[n].coverage = 255;
                     int len = 1;
-                    while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
+                    while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
                         ++src_x;
                         ++len;
                     }
@@ -3486,82 +3452,13 @@ QRect QRasterPaintEngine::clipBoundingRect() const
     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
 }
 
-static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
-{
-    Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
-
-    QVarLengthArray<short, 4096> buffer;
-
-    QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
-    QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
-    result->initialize();
-
-    for (int y = 0; y < c1->clipSpanHeight; ++y) {
-        const QSpan *c1_spans = c1ClipLines[y].spans;
-        int c1_count = c1ClipLines[y].count;
-        const QSpan *c2_spans = c2ClipLines[y].spans;
-        int c2_count = c2ClipLines[y].count;
-
-        if (c1_count == 0 && c2_count == 0)
-            continue;
-        if (c1_count == 0) {
-            result->appendSpans(c2_spans, c2_count);
-            continue;
-        } else if (c2_count == 0) {
-            result->appendSpans(c1_spans, c1_count);
-            continue;
-        }
-
-        // we need to merge the two
-
-        // find required length
-        int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
-                c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
-        buffer.resize(max);
-        memset(buffer.data(), 0, buffer.size() * sizeof(short));
-
-        // Fill with old spans.
-        for (int i = 0; i < c1_count; ++i) {
-            const QSpan *cs = c1_spans + i;
-            for (int j=cs->x; j<cs->x + cs->len; ++j)
-                buffer[j] = cs->coverage;
-        }
-
-        // Fill with new spans
-        for (int i = 0; i < c2_count; ++i) {
-            const QSpan *cs = c2_spans + i;
-            for (int j = cs->x; j < cs->x + cs->len; ++j) {
-                buffer[j] += cs->coverage;
-                if (buffer[j] > 255)
-                    buffer[j] = 255;
-            }
-        }
-
-        int x = 0;
-        while (x<max) {
-
-            // Skip to next span
-            while (x < max && buffer[x] == 0) ++x;
-            if (x >= max) break;
-
-            int sx = x;
-            int coverage = buffer[x];
-
-            // Find length of span
-            while (x < max && buffer[x] == coverage)
-                ++x;
-
-            result->appendSpan(sx, x - sx, y, coverage);
-        }
-    }
-}
-
 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
 {
     Q_Q(QRasterPaintEngine);
     QRasterPaintEngineState *s = q->state();
 
     rasterizer->setAntialiased(s->flags.antialiased);
+    rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
 
     QRect clipRect(deviceRect);
     ProcessSpans blend;
@@ -3609,6 +3506,11 @@ extern "C" {
     int q_gray_rendered_spans(QT_FT_Raster raster);
 }
 
+static inline uchar *alignAddress(uchar *address, quintptr alignmentMask)
+{
+    return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
+}
+
 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
                                           ProcessSpans callback,
                                           void *userData, QRasterBuffer *)
@@ -3621,6 +3523,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
 
     if (!s->flags.antialiased) {
         rasterizer->setAntialiased(s->flags.antialiased);
+        rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
         rasterizer->setClipRect(deviceRect);
         rasterizer->initialize(callback, userData);
 
@@ -3636,19 +3539,10 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
     // minimize memory reallocations. However if initial size for
     // raster pool is changed for lower value, reallocations will
     // occur normally.
-    const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
-    int rasterPoolSize = rasterPoolInitialSize;
-    unsigned char *rasterPoolBase;
-#if defined(Q_OS_WIN64)
-    rasterPoolBase =
-        // We make use of setjmp and longjmp in qgrayraster.c which requires
-        // 16-byte alignment, hence we hardcode this requirement here..
-        (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
-    unsigned char rasterPoolOnStack[rasterPoolInitialSize];
-    rasterPoolBase = rasterPoolOnStack;
-#endif
-    Q_CHECK_PTR(rasterPoolBase);
+    int rasterPoolSize = MINIMUM_POOL_SIZE;
+    uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
+    uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
+    uchar *rasterPoolOnHeap = 0;
 
     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
 
@@ -3684,31 +3578,20 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
 
         // Out of memory, reallocate some more and try again...
         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
-            int new_size = rasterPoolSize * 2;
-            if (new_size > 1024 * 1024) {
+            rasterPoolSize *= 2;
+            if (rasterPoolSize > 1024 * 1024) {
                 qWarning("QPainter: Rasterization of primitive failed");
                 break;
             }
 
             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
 
-#if defined(Q_OS_WIN64)
-            _aligned_free(rasterPoolBase);
-#else
-            if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
-                free(rasterPoolBase);
-#endif
+            free(rasterPoolOnHeap);
+            rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
 
-            rasterPoolSize = new_size;
-            rasterPoolBase =
-#if defined(Q_OS_WIN64)
-                // We make use of setjmp and longjmp in qgrayraster.c which requires
-                // 16-byte alignment, hence we hardcode this requirement here..
-                (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
-#else
-                (unsigned char *) malloc(rasterPoolSize);
-#endif
-            Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+            Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
+
+            rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
 
             qt_ft_grays_raster.raster_done(*grayRaster.data());
             qt_ft_grays_raster.raster_new(grayRaster.data());
@@ -3718,12 +3601,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
         }
     }
 
-#if defined(Q_OS_WIN64)
-    _aligned_free(rasterPoolBase);
-#else
-    if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
-        free(rasterPoolBase);
-#endif
+    free(rasterPoolOnHeap);
 }
 
 void QRasterPaintEnginePrivate::recalculateFastImages()
@@ -4221,7 +4099,6 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData)
         }
         break;
 
-    case Qt::UniteClip:
     case Qt::ReplaceClip:
         clipData->newClip->appendSpans(spans, count);
         break;
@@ -4711,7 +4588,7 @@ void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
     txop = inv.type();
     bilinear = bilin;
 
-    const bool affine = !m13 && !m23;
+    const bool affine = inv.isAffine();
     fast_matrix = affine
         && m11 * m11 + m21 * m21 < 1e4
         && m12 * m12 + m22 * m22 < 1e4
@@ -4721,8 +4598,6 @@ void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
     adjustSpanMethods();
 }
 
-extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
-
 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
 {
     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
@@ -4767,25 +4642,133 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _
     adjustSpanMethods();
 }
 
-
 /*!
-    \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
-    \overload
+    \internal
+    \a x and \a y is relative to the midpoint of \a rect.
+*/
+static inline void drawEllipsePoints(int x, int y, int length,
+                                     const QRect &rect,
+                                     const QRect &clip,
+                                     ProcessSpans pen_func, ProcessSpans brush_func,
+                                     QSpanData *pen_data, QSpanData *brush_data)
+{
+    if (length == 0)
+        return;
 
-    Draws the first \a pointCount points in the buffer \a points
+    QT_FT_Span outline[4];
+    const int midx = rect.x() + (rect.width() + 1) / 2;
+    const int midy = rect.y() + (rect.height() + 1) / 2;
+
+    x = x + midx;
+    y = midy - y;
+
+    // topleft
+    outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
+    outline[0].len = qMin(length, x - outline[0].x);
+    outline[0].y = y;
+    outline[0].coverage = 255;
+
+    // topright
+    outline[1].x = x;
+    outline[1].len = length;
+    outline[1].y = y;
+    outline[1].coverage = 255;
+
+    // bottomleft
+    outline[2].x = outline[0].x;
+    outline[2].len = outline[0].len;
+    outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
+    outline[2].coverage = 255;
+
+    // bottomright
+    outline[3].x = x;
+    outline[3].len = length;
+    outline[3].y = outline[2].y;
+    outline[3].coverage = 255;
+
+    if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
+        QT_FT_Span fill[2];
+
+        // top fill
+        fill[0].x = outline[0].x + outline[0].len - 1;
+        fill[0].len = qMax(0, outline[1].x - fill[0].x);
+        fill[0].y = outline[1].y;
+        fill[0].coverage = 255;
+
+        // bottom fill
+        fill[1].x = outline[2].x + outline[2].len - 1;
+        fill[1].len = qMax(0, outline[3].x - fill[1].x);
+        fill[1].y = outline[3].y;
+        fill[1].coverage = 255;
+
+        int n = (fill[0].y >= fill[1].y ? 1 : 2);
+        n = qt_intersect_spans(fill, n, clip);
+        if (n > 0)
+            brush_func(n, fill, brush_data);
+    }
+    if (pen_func) {
+        int n = (outline[1].y >= outline[2].y ? 2 : 4);
+        n = qt_intersect_spans(outline, n, clip);
+        if (n > 0)
+            pen_func(n, outline, pen_data);
+    }
+}
 
-    The default implementation converts the first \a pointCount QPoints in \a points
-    to QPointFs and calls the floating point version of drawPoints.
+/*!
+    \internal
+    Draws an ellipse using the integer point midpoint algorithm.
 */
+static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
+                                   ProcessSpans pen_func, ProcessSpans brush_func,
+                                   QSpanData *pen_data, QSpanData *brush_data)
+{
+    const qreal a = qreal(rect.width()) / 2;
+    const qreal b = qreal(rect.height()) / 2;
+    qreal d = b*b - (a*a*b) + 0.25*a*a;
+
+    int x = 0;
+    int y = (rect.height() + 1) / 2;
+    int startx = x;
+
+    // region 1
+    while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
+        if (d < 0) { // select E
+            d += b*b*(2*x + 3);
+            ++x;
+        } else {     // select SE
+            d += b*b*(2*x + 3) + a*a*(-2*y + 2);
+            drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
+                              pen_func, brush_func, pen_data, brush_data);
+            startx = ++x;
+            --y;
+        }
+    }
+    drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
+                      pen_func, brush_func, pen_data, brush_data);
+
+    // region 2
+    d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
+    const int miny = rect.height() & 0x1;
+    while (y > miny) {
+        if (d < 0) { // select SE
+            d += b*b*(2*x + 2) + a*a*(-2*y + 3);
+            ++x;
+        } else {     // select S
+            d += a*a*(-2*y + 3);
+        }
+        --y;
+        drawEllipsePoints(x, y, 1, rect, clip,
+                          pen_func, brush_func, pen_data, brush_data);
+    }
+}
 
 /*!
-    \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
+    \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
     \overload
-
-    Reimplement this function to draw the largest ellipse that can be
-    contained within rectangle \a rect.
+    \reimp
 */
 
+
 #ifdef QT_DEBUG_DRAW
 void dumpClip(int width, int height, const QClipData *clip)
 {