src/gui/painting/qpaintengine_raster.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
--- a/src/gui/painting/qpaintengine_raster.cpp	Tue Jul 06 15:10:48 2010 +0300
+++ b/src/gui/painting/qpaintengine_raster.cpp	Wed Aug 18 10:37:55 2010 +0300
@@ -68,6 +68,7 @@
 //   #include <private/qrasterizer_p.h>
 #include <private/qimage_p.h>
 #include <private/qstatictext_p.h>
+#include "qmemrotate_p.h"
 
 #include "qpaintengine_raster_p.h"
 //   #include "qbezier_p.h"
@@ -344,7 +345,7 @@
     // The antialiasing raster.
     d->grayRaster.reset(new QT_FT_Raster);
     Q_CHECK_PTR(d->grayRaster.data());
-    if (qt_ft_grays_raster.raster_new(0, d->grayRaster.data()))
+    if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
 
 
@@ -441,8 +442,9 @@
 
     if (device->devType() == QInternal::Pixmap) {
         QPixmap *pixmap = static_cast<QPixmap *>(device);
-        if (pixmap->data->classId() == QPixmapData::RasterClass)
-            d->device = pixmap->data->buffer();
+        QPixmapData *pd = pixmap->pixmapData();
+        if (pd->classId() == QPixmapData::RasterClass)
+            d->device = pd->buffer();
     } else {
         d->device = device;
     }
@@ -457,13 +459,12 @@
 
     QRasterPaintEngineState *s = state();
     ensureOutlineMapper();
-    d->outlineMapper->m_clip_rect = d->deviceRect.adjusted(-10, -10, 10, 10);
-
-    // This is the upp
-    QRect bounds(-QT_RASTER_COORD_LIMIT, -QT_RASTER_COORD_LIMIT,
-                 QT_RASTER_COORD_LIMIT*2 - 1, QT_RASTER_COORD_LIMIT * 2 - 1);
-    d->outlineMapper->m_clip_rect = bounds.intersected(d->outlineMapper->m_clip_rect);
-
+    d->outlineMapper->m_clip_rect = d->deviceRect;
+
+    if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
+        d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
+    if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
+        d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
 
     d->rasterizer->setClipRect(d->deviceRect);
 
@@ -2358,8 +2359,9 @@
     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
 #endif
 
-    if (pixmap.data->classId() == QPixmapData::RasterClass) {
-        const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
+    QPixmapData *pd = pixmap.pixmapData();
+    if (pd->classId() == QPixmapData::RasterClass) {
+        const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
         if (image.depth() == 1) {
             Q_D(QRasterPaintEngine);
             QRasterPaintEngineState *s = state();
@@ -2398,8 +2400,9 @@
     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
 #endif
 
-    if (pixmap.data->classId() == QPixmapData::RasterClass) {
-        const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
+    QPixmapData* pd = pixmap.pixmapData();
+    if (pd->classId() == QPixmapData::RasterClass) {
+        const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
         if (image.depth() == 1) {
             Q_D(QRasterPaintEngine);
             QRasterPaintEngineState *s = state();
@@ -2416,7 +2419,9 @@
             drawImage(r, image, sr);
         }
     } else {
-        const QImage image = pixmap.toImage();
+        QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
+        const QImage image = pd->toImage(clippedSource);
+        QRectF translatedSource = sr.translated(-clippedSource.topLeft());
         if (image.depth() == 1) {
             Q_D(QRasterPaintEngine);
             QRasterPaintEngineState *s = state();
@@ -2427,10 +2432,10 @@
                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
                 return;
             } else {
-                drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
+                drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
             }
         } else {
-            drawImage(r, image, sr);
+            drawImage(r, image, translatedSource);
         }
     }
 }
@@ -2518,6 +2523,41 @@
     return QRectF(r.topLeft() * t, r.bottomRight() * t);
 }
 
+namespace {
+    enum RotationType {
+        Rotation90,
+        Rotation180,
+        Rotation270,
+        NoRotation
+    };
+
+    inline RotationType qRotationType(const QTransform &transform)
+    {
+        QTransform::TransformationType type = transform.type();
+
+        if (type > QTransform::TxRotate)
+            return NoRotation;
+
+        if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
+            && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
+            return Rotation90;
+
+        if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
+            && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
+            return Rotation180;
+
+        if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
+            && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
+            return Rotation270;
+
+        return NoRotation;
+    }
+
+    inline bool isPixelAligned(const QRectF &rect) {
+        return QRectF(rect.toRect()) == rect;
+    }
+}
+
 /*!
     \reimp
 */
@@ -2579,9 +2619,62 @@
 
     const QClipData *clip = d->clip();
 
+    if (s->matrix.type() > QTransform::TxTranslate
+        && !stretch_sr
+        && (!clip || clip->hasRectClip)
+        && s->intOpacity == 256
+        && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
+            || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
+        && d->rasterBuffer->format == img.format()
+        && (d->rasterBuffer->format == QImage::Format_RGB16
+            || d->rasterBuffer->format == QImage::Format_RGB32
+            || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
+                && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
+    {
+        RotationType rotationType = qRotationType(s->matrix);
+
+        if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
+            QRectF transformedTargetRect = s->matrix.mapRect(r);
+
+            if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
+                || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
+            {
+                QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
+                if (clippedTransformedTargetRect.isNull())
+                    return;
+
+                QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
+
+                QRect clippedSourceRect
+                    = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
+                            clippedTargetRect.width(), clippedTargetRect.height()).toRect();
+
+                uint dbpl = d->rasterBuffer->bytesPerLine();
+                uint sbpl = img.bytesPerLine();
+
+                uchar *dst = d->rasterBuffer->buffer();
+                uint bpp = img.depth() >> 3;
+
+                const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
+                uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
+
+                uint cw = clippedSourceRect.width();
+                uint ch = clippedSourceRect.height();
+
+                qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
+
+                return;
+            }
+        }
+    }
+
     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
 
-        if (s->flags.fast_images) {
+        QRectF targetBounds = s->matrix.mapRect(r);
+        bool exceedsPrecision = targetBounds.width() > 0xffff
+                                || targetBounds.height() > 0xffff;
+
+        if (s->flags.fast_images && !exceedsPrecision) {
             if (s->matrix.type() > QTransform::TxScale) {
                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
                 if (func && (!clip || clip->hasRectClip)) {
@@ -2703,8 +2796,9 @@
 
     QImage image;
 
-    if (pixmap.data->classId() == QPixmapData::RasterClass) {
-        image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
+    QPixmapData *pd = pixmap.pixmapData();
+    if (pd->classId() == QPixmapData::RasterClass) {
+        image = static_cast<QRasterPixmapData *>(pd)->image;
     } else {
         image = pixmap.toImage();
     }
@@ -3680,6 +3774,7 @@
     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();
@@ -4076,7 +4171,11 @@
         return;
     }
 
-    const int rasterPoolInitialSize = 8192;
+    // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
+    // 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_WS_WIN64)
@@ -4120,7 +4219,7 @@
         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
 
         // Out of memory, reallocate some more and try again...
-        if (error == -6) { // -6 is Result_err_OutOfMemory
+        if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
             int new_size = rasterPoolSize * 2;
             if (new_size > 1024 * 1024) {
                 qWarning("QPainter: Rasterization of primitive failed");
@@ -4146,7 +4245,7 @@
             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
 
             qt_ft_grays_raster.raster_done(*grayRaster.data());
-            qt_ft_grays_raster.raster_new(0, grayRaster.data());
+            qt_ft_grays_raster.raster_new(grayRaster.data());
             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
         } else {
             done = true;