src/gui/painting/qpaintengine_raster.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtCore/qglobal.h>
       
    43 
       
    44 #define QT_FT_BEGIN_HEADER
       
    45 #define QT_FT_END_HEADER
       
    46 
       
    47 #include <private/qrasterdefs_p.h>
       
    48 #include <private/qgrayraster_p.h>
       
    49 
       
    50 #include <qpainterpath.h>
       
    51 #include <qdebug.h>
       
    52 #include <qhash.h>
       
    53 #include <qlabel.h>
       
    54 #include <qbitmap.h>
       
    55 #include <qmath.h>
       
    56 
       
    57 #if defined (Q_WS_X11)
       
    58 #  include <private/qfontengine_ft_p.h>
       
    59 #endif
       
    60 
       
    61 //   #include <private/qdatabuffer_p.h>
       
    62 //   #include <private/qpainter_p.h>
       
    63 #include <private/qmath_p.h>
       
    64 #include <private/qtextengine_p.h>
       
    65 #include <private/qfontengine_p.h>
       
    66 #include <private/qpixmap_raster_p.h>
       
    67 //   #include <private/qpolygonclipper_p.h>
       
    68 //   #include <private/qrasterizer_p.h>
       
    69 #include <private/qimage_p.h>
       
    70 
       
    71 #include "qpaintengine_raster_p.h"
       
    72 //   #include "qbezier_p.h"
       
    73 #include "qoutlinemapper_p.h"
       
    74 
       
    75 #if defined(Q_WS_WIN)
       
    76 #  include <qt_windows.h>
       
    77 #  include <qvarlengtharray.h>
       
    78 #  include <private/qfontengine_p.h>
       
    79 #  if defined(Q_OS_WINCE)
       
    80 #    include "qguifunctions_wince.h"
       
    81 #  endif
       
    82 #elif defined(Q_WS_MAC)
       
    83 #  include <private/qt_mac_p.h>
       
    84 #  include <private/qpixmap_mac_p.h>
       
    85 #  include <private/qpaintengine_mac_p.h>
       
    86 #elif defined(Q_WS_QWS)
       
    87 #  if !defined(QT_NO_FREETYPE)
       
    88 #    include <private/qfontengine_ft_p.h>
       
    89 #  endif
       
    90 #  if !defined(QT_NO_QWS_QPF2)
       
    91 #    include <private/qfontengine_qpf_p.h>
       
    92 #  endif
       
    93 #  include <private/qabstractfontengine_p.h>
       
    94 #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
       
    95 #  include <private/qfontengine_s60_p.h>
       
    96 #endif
       
    97 
       
    98 #if defined(Q_WS_WIN64)
       
    99 #  include <malloc.h>
       
   100 #endif
       
   101 #include <limits.h>
       
   102 
       
   103 #if defined(QT_NO_FPU) || (_MSC_VER >= 1300 && _MSC_VER < 1400)
       
   104 #  define FLOATING_POINT_BUGGY_OR_NO_FPU
       
   105 #endif
       
   106 
       
   107 QT_BEGIN_NAMESPACE
       
   108 
       
   109 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
       
   110 
       
   111 #define qreal_to_fixed_26_6(f) (int(f * 64))
       
   112 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
       
   113 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
       
   114 
       
   115 // #define QT_DEBUG_DRAW
       
   116 #ifdef QT_DEBUG_DRAW
       
   117 void dumpClip(int width, int height, const QClipData *clip);
       
   118 #endif
       
   119 
       
   120 #define QT_FAST_SPANS
       
   121 
       
   122 
       
   123 // A little helper macro to get a better approximation of dimensions.
       
   124 // If we have a rect that starting at 0.5 of width 3.5 it should span
       
   125 // 4 pixels.
       
   126 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
       
   127 
       
   128 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
       
   129 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
       
   130 
       
   131 #ifdef Q_WS_WIN
       
   132 extern bool qt_cleartype_enabled;
       
   133 #endif
       
   134 
       
   135 #ifdef Q_WS_MAC
       
   136 extern bool qt_applefontsmoothing_enabled;
       
   137 #endif
       
   138 
       
   139 
       
   140 /********************************************************************************
       
   141  * Span functions
       
   142  */
       
   143 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
       
   144 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
       
   145 static void qt_span_clip(int count, const QSpan *spans, void *userData);
       
   146 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
       
   147 
       
   148 struct ClipData
       
   149 {
       
   150     QClipData *oldClip;
       
   151     QClipData *newClip;
       
   152     Qt::ClipOperation operation;
       
   153 };
       
   154 
       
   155 enum LineDrawMode {
       
   156     LineDrawClipped,
       
   157     LineDrawNormal,
       
   158     LineDrawIncludeLastPixel
       
   159 };
       
   160 
       
   161 static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
       
   162                                 LineDrawMode style, const QIntRect &rect);
       
   163 static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
       
   164                                        QPen *pen, ProcessSpans span_func, QSpanData *data,
       
   165                                        LineDrawMode style, const QIntRect &devRect,
       
   166                                        int *patternOffset);
       
   167 // static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2,
       
   168 //                                 ProcessSpans span_func, QSpanData *data,
       
   169 //                                 LineDrawMode style, const QRect &devRect);
       
   170 
       
   171 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
       
   172                                    ProcessSpans pen_func, ProcessSpans brush_func,
       
   173                                    QSpanData *pen_data, QSpanData *brush_data);
       
   174 
       
   175 struct QRasterFloatPoint {
       
   176     qreal x;
       
   177     qreal y;
       
   178 };
       
   179 
       
   180 #ifdef QT_DEBUG_DRAW
       
   181 static const QRectF boundingRect(const QPointF *points, int pointCount)
       
   182 {
       
   183     const QPointF *e = points;
       
   184     const QPointF *last = points + pointCount;
       
   185     qreal minx, maxx, miny, maxy;
       
   186     minx = maxx = e->x();
       
   187     miny = maxy = e->y();
       
   188     while (++e < last) {
       
   189         if (e->x() < minx)
       
   190             minx = e->x();
       
   191         else if (e->x() > maxx)
       
   192             maxx = e->x();
       
   193         if (e->y() < miny)
       
   194             miny = e->y();
       
   195         else if (e->y() > maxy)
       
   196             maxy = e->y();
       
   197     }
       
   198     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
       
   199 }
       
   200 #endif
       
   201 
       
   202 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
       
   203     return (elementCount == 5 // 5-point polygon, check for closed rect
       
   204             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
       
   205             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
       
   206             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
       
   207             && pts[0] < pts[4] && pts[1] < pts[5]
       
   208             ) ||
       
   209            (elementCount == 4 // 4-point polygon, check for unclosed rect
       
   210             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
       
   211             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
       
   212             && pts[0] < pts[4] && pts[1] < pts[5]
       
   213             );
       
   214 }
       
   215 
       
   216 
       
   217 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
       
   218 {
       
   219     ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
       
   220 }
       
   221 
       
   222 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
       
   223 {
       
   224     ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
       
   225 }
       
   226 
       
   227 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
       
   228                              qfixed c2x, qfixed c2y,
       
   229                              qfixed ex, qfixed ey,
       
   230                              void *data)
       
   231 {
       
   232     ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
       
   233                                        QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
       
   234                                        QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
       
   235 }
       
   236 
       
   237 
       
   238 #if !defined(QT_NO_DEBUG) && 0
       
   239 static void qt_debug_path(const QPainterPath &path)
       
   240 {
       
   241     const char *names[] = {
       
   242         "MoveTo     ",
       
   243         "LineTo     ",
       
   244         "CurveTo    ",
       
   245         "CurveToData"
       
   246     };
       
   247 
       
   248     fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
       
   249     for (int i=0; i<path.elementCount(); ++i) {
       
   250         const QPainterPath::Element &e = path.elementAt(i);
       
   251         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
       
   252         fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
       
   253     }
       
   254 }
       
   255 #endif
       
   256 
       
   257 
       
   258 
       
   259 /*!
       
   260     \class QRasterPaintEngine
       
   261     \preliminary
       
   262     \ingroup qws
       
   263     \since 4.2
       
   264 
       
   265     \brief The QRasterPaintEngine class enables hardware acceleration
       
   266     of painting operations in Qt for Embedded Linux.
       
   267 
       
   268     Note that this functionality is only available in
       
   269     \l{Qt for Embedded Linux}.
       
   270 
       
   271     In \l{Qt for Embedded Linux}, painting is a pure software
       
   272     implementation. But starting with Qt 4.2, it is
       
   273     possible to add an accelerated graphics driver to take advantage
       
   274     of available hardware resources.
       
   275 
       
   276     Hardware acceleration is accomplished by creating a custom screen
       
   277     driver, accelerating the copying from memory to the screen, and
       
   278     implementing a custom paint engine accelerating the various
       
   279     painting operations. Then a custom paint device (derived from the
       
   280     QCustomRasterPaintDevice class) and a custom window surface
       
   281     (derived from QWSWindowSurface) must be implemented to make
       
   282     \l{Qt for Embedded Linux} aware of the accelerated driver.
       
   283 
       
   284     \note The QRasterPaintEngine class does not support 8-bit images.
       
   285     Instead, they need to be converted to a supported format, such as
       
   286     QImage::Format_ARGB32_Premultiplied.
       
   287 
       
   288     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
       
   289     documentation for details.
       
   290 
       
   291     \sa QCustomRasterPaintDevice, QPaintEngine
       
   292 */
       
   293 
       
   294 /*!
       
   295     \fn Type QRasterPaintEngine::type() const
       
   296     \reimp
       
   297 */
       
   298 
       
   299 /*!
       
   300     \typedef QSpan
       
   301     \relates QRasterPaintEngine
       
   302 
       
   303     A struct equivalent to QT_FT_Span, containing a position (x,
       
   304     y), the span's length in pixels and its color/coverage (a value
       
   305     ranging from 0 to 255).
       
   306 */
       
   307 
       
   308 /*!
       
   309     \since 4.5
       
   310 
       
   311     Creates a raster based paint engine for operating on the given
       
   312     \a device, with the complete set of \l
       
   313     {QPaintEngine::PaintEngineFeature}{paint engine features and
       
   314     capabilities}.
       
   315 */
       
   316 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
       
   317     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
       
   318 {
       
   319     d_func()->device = device;
       
   320     init();
       
   321 }
       
   322 
       
   323 /*!
       
   324     \internal
       
   325 */
       
   326 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
       
   327     : QPaintEngineEx(dd)
       
   328 {
       
   329     d_func()->device = device;
       
   330     init();
       
   331 }
       
   332 
       
   333 void QRasterPaintEngine::init()
       
   334 {
       
   335     Q_D(QRasterPaintEngine);
       
   336 
       
   337 
       
   338 #ifdef Q_WS_WIN
       
   339     d->hdc = 0;
       
   340 #endif
       
   341 
       
   342     d->rasterPoolSize = 8192;
       
   343     d->rasterPoolBase =
       
   344 #if defined(Q_WS_WIN64)
       
   345         // We make use of setjmp and longjmp in qgrayraster.c which requires
       
   346         // 16-byte alignment, hence we hardcode this requirement here..
       
   347         (unsigned char *) _aligned_malloc(d->rasterPoolSize, sizeof(void*) * 2);
       
   348 #else
       
   349         (unsigned char *) malloc(d->rasterPoolSize);
       
   350 #endif
       
   351     Q_CHECK_PTR(d->rasterPoolBase);
       
   352 
       
   353     // The antialiasing raster.
       
   354     d->grayRaster.reset(new QT_FT_Raster);
       
   355     Q_CHECK_PTR(d->grayRaster.data());
       
   356     if (qt_ft_grays_raster.raster_new(0, d->grayRaster.data()))
       
   357         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
       
   358 
       
   359 
       
   360     qt_ft_grays_raster.raster_reset(*d->grayRaster.data(), d->rasterPoolBase, d->rasterPoolSize);
       
   361 
       
   362     d->rasterizer.reset(new QRasterizer);
       
   363     d->rasterBuffer.reset(new QRasterBuffer());
       
   364     d->outlineMapper.reset(new QOutlineMapper);
       
   365     d->outlinemapper_xform_dirty = true;
       
   366 
       
   367     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
       
   368     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
       
   369     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
       
   370 
       
   371     d->baseClip.reset(new QClipData(d->device->height()));
       
   372     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
       
   373 
       
   374     d->image_filler.init(d->rasterBuffer.data(), this);
       
   375     d->image_filler.type = QSpanData::Texture;
       
   376 
       
   377     d->image_filler_xform.init(d->rasterBuffer.data(), this);
       
   378     d->image_filler_xform.type = QSpanData::Texture;
       
   379 
       
   380     d->solid_color_filler.init(d->rasterBuffer.data(), this);
       
   381     d->solid_color_filler.type = QSpanData::Solid;
       
   382 
       
   383     d->deviceDepth = d->device->depth();
       
   384 
       
   385     d->mono_surface = false;
       
   386     gccaps &= ~PorterDuff;
       
   387 
       
   388     QImage::Format format = QImage::Format_Invalid;
       
   389 
       
   390     switch (d->device->devType()) {
       
   391     case QInternal::Pixmap:
       
   392         qWarning("QRasterPaintEngine: unsupported for pixmaps...");
       
   393         break;
       
   394     case QInternal::Image:
       
   395         format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
       
   396         break;
       
   397 #ifdef Q_WS_QWS
       
   398     case QInternal::CustomRaster:
       
   399         d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
       
   400         break;
       
   401 #endif
       
   402     default:
       
   403         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
       
   404         d->device = 0;
       
   405         return;
       
   406     }
       
   407 
       
   408     switch (format) {
       
   409     case QImage::Format_MonoLSB:
       
   410     case QImage::Format_Mono:
       
   411         d->mono_surface = true;
       
   412         break;
       
   413     case QImage::Format_ARGB8565_Premultiplied:
       
   414     case QImage::Format_ARGB8555_Premultiplied:
       
   415     case QImage::Format_ARGB6666_Premultiplied:
       
   416     case QImage::Format_ARGB4444_Premultiplied:
       
   417     case QImage::Format_ARGB32_Premultiplied:
       
   418     case QImage::Format_ARGB32:
       
   419         gccaps |= PorterDuff;
       
   420         break;
       
   421     case QImage::Format_RGB32:
       
   422     case QImage::Format_RGB444:
       
   423     case QImage::Format_RGB555:
       
   424     case QImage::Format_RGB666:
       
   425     case QImage::Format_RGB888:
       
   426     case QImage::Format_RGB16:
       
   427         break;
       
   428     default:
       
   429         break;
       
   430     }
       
   431 }
       
   432 
       
   433 
       
   434 
       
   435 
       
   436 /*!
       
   437     Destroys this paint engine.
       
   438 */
       
   439 QRasterPaintEngine::~QRasterPaintEngine()
       
   440 {
       
   441     Q_D(QRasterPaintEngine);
       
   442 
       
   443 #if defined(Q_WS_WIN64)
       
   444     _aligned_free(d->rasterPoolBase);
       
   445 #else
       
   446     free(d->rasterPoolBase);
       
   447 #endif
       
   448 
       
   449     qt_ft_grays_raster.raster_done(*d->grayRaster.data());
       
   450 }
       
   451 
       
   452 /*!
       
   453     \reimp
       
   454 */
       
   455 bool QRasterPaintEngine::begin(QPaintDevice *device)
       
   456 {
       
   457     Q_D(QRasterPaintEngine);
       
   458 
       
   459     if (device->devType() == QInternal::Pixmap) {
       
   460         QPixmap *pixmap = static_cast<QPixmap *>(device);
       
   461         if (pixmap->data->classId() == QPixmapData::RasterClass)
       
   462             d->device = pixmap->data->buffer();
       
   463     } else {
       
   464         d->device = device;
       
   465     }
       
   466 
       
   467     // Make sure QPaintEngine::paintDevice() returns the proper device.
       
   468     d->pdev = d->device;
       
   469 
       
   470     Q_ASSERT(d->device->devType() == QInternal::Image
       
   471              || d->device->devType() == QInternal::CustomRaster);
       
   472 
       
   473     d->systemStateChanged();
       
   474 
       
   475     QRasterPaintEngineState *s = state();
       
   476     ensureOutlineMapper();
       
   477     d->outlineMapper->m_clip_rect = d->deviceRect.adjusted(-10, -10, 10, 10);
       
   478     QRect bounds(-QT_RASTER_COORD_LIMIT, -QT_RASTER_COORD_LIMIT,
       
   479                  2*QT_RASTER_COORD_LIMIT, 2*QT_RASTER_COORD_LIMIT);
       
   480     d->outlineMapper->m_clip_rect = bounds.intersected(d->outlineMapper->m_clip_rect);
       
   481 
       
   482 
       
   483     d->rasterizer->setClipRect(d->deviceRect);
       
   484 
       
   485     s->penData.init(d->rasterBuffer.data(), this);
       
   486     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
       
   487     s->stroker = &d->basicStroker;
       
   488     d->basicStroker.setClipRect(d->deviceRect);
       
   489 
       
   490     s->brushData.init(d->rasterBuffer.data(), this);
       
   491     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
       
   492 
       
   493     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
       
   494 
       
   495     setDirty(DirtyBrushOrigin);
       
   496 
       
   497 #ifdef QT_DEBUG_DRAW
       
   498     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
       
   499              << ") devType:" << device->devType()
       
   500              << "devRect:" << d->deviceRect;
       
   501     if (d->baseClip) {
       
   502         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
       
   503     }
       
   504 #endif
       
   505 
       
   506 #if defined(Q_WS_WIN)
       
   507     d->isPlain45DegreeRotation = true;
       
   508 #endif
       
   509 
       
   510     if (d->mono_surface)
       
   511         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
       
   512 #if defined(Q_WS_WIN)
       
   513     else if (qt_cleartype_enabled)
       
   514 #elif defined (Q_WS_MAC)
       
   515     else if (qt_applefontsmoothing_enabled)
       
   516 #else
       
   517     else if (false)
       
   518 #endif
       
   519     {
       
   520         QImage::Format format = static_cast<QImage *>(d->device)->format();
       
   521         if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
       
   522             d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
       
   523         else
       
   524             d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
       
   525     } else
       
   526         d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
       
   527 
       
   528     setActive(true);
       
   529     return true;
       
   530 }
       
   531 
       
   532 /*!
       
   533     \reimp
       
   534 */
       
   535 bool QRasterPaintEngine::end()
       
   536 {
       
   537 #ifdef QT_DEBUG_DRAW
       
   538     Q_D(QRasterPaintEngine);
       
   539     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
       
   540     if (d->baseClip) {
       
   541         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
       
   542     }
       
   543 #endif
       
   544 
       
   545     return true;
       
   546 }
       
   547 
       
   548 /*!
       
   549     \internal
       
   550 */
       
   551 void QRasterPaintEngine::releaseBuffer()
       
   552 {
       
   553     Q_D(QRasterPaintEngine);
       
   554     d->rasterBuffer.reset(new QRasterBuffer);
       
   555 }
       
   556 
       
   557 /*!
       
   558     \internal
       
   559 */
       
   560 QSize QRasterPaintEngine::size() const
       
   561 {
       
   562     Q_D(const QRasterPaintEngine);
       
   563     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
       
   564 }
       
   565 
       
   566 /*!
       
   567     \internal
       
   568 */
       
   569 #ifndef QT_NO_DEBUG
       
   570 void QRasterPaintEngine::saveBuffer(const QString &s) const
       
   571 {
       
   572     Q_D(const QRasterPaintEngine);
       
   573     d->rasterBuffer->bufferImage().save(s, "PNG");
       
   574 }
       
   575 #endif
       
   576 
       
   577 /*!
       
   578     \internal
       
   579 */
       
   580 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
       
   581 {
       
   582     QRasterPaintEngineState *s = state();
       
   583     // FALCON: get rid of this line, see drawImage call below.
       
   584     s->matrix = matrix;
       
   585     QTransform::TransformationType txop = s->matrix.type();
       
   586 
       
   587     switch (txop) {
       
   588 
       
   589     case QTransform::TxNone:
       
   590         s->flags.int_xform = true;
       
   591         break;
       
   592 
       
   593     case QTransform::TxTranslate:
       
   594         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
       
   595                             && qreal(int(s->matrix.dy())) == s->matrix.dy();
       
   596         break;
       
   597 
       
   598     case QTransform::TxScale:
       
   599         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
       
   600                             && qreal(int(s->matrix.dy())) == s->matrix.dy()
       
   601                             && qreal(int(s->matrix.m11())) == s->matrix.m11()
       
   602                             && qreal(int(s->matrix.m22())) == s->matrix.m22();
       
   603         break;
       
   604 
       
   605     default: // shear / perspective...
       
   606         s->flags.int_xform = false;
       
   607         break;
       
   608     }
       
   609 
       
   610     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
       
   611 
       
   612     ensureOutlineMapper();
       
   613 
       
   614 #ifdef Q_WS_WIN
       
   615     Q_D(QRasterPaintEngine);
       
   616     d->isPlain45DegreeRotation = false;
       
   617     if (txop >= QTransform::TxRotate) {
       
   618         d->isPlain45DegreeRotation =
       
   619             (qFuzzyIsNull(matrix.m11())
       
   620              && qFuzzyIsNull(matrix.m12() - qreal(1))
       
   621              && qFuzzyIsNull(matrix.m21() + qreal(1))
       
   622              && qFuzzyIsNull(matrix.m22())
       
   623                 )
       
   624             ||
       
   625             (qFuzzyIsNull(matrix.m11() + qreal(1))
       
   626              && qFuzzyIsNull(matrix.m12())
       
   627              && qFuzzyIsNull(matrix.m21())
       
   628              && qFuzzyIsNull(matrix.m22() + qreal(1))
       
   629                 )
       
   630             ||
       
   631             (qFuzzyIsNull(matrix.m11())
       
   632              && qFuzzyIsNull(matrix.m12() + qreal(1))
       
   633              && qFuzzyIsNull(matrix.m21() - qreal(1))
       
   634              && qFuzzyIsNull(matrix.m22())
       
   635                 )
       
   636             ;
       
   637     }
       
   638 #endif
       
   639 
       
   640 }
       
   641 
       
   642 
       
   643 
       
   644 QRasterPaintEngineState::~QRasterPaintEngineState()
       
   645 {
       
   646     if (flags.has_clip_ownership)
       
   647         delete clip;
       
   648 }
       
   649 
       
   650 
       
   651 QRasterPaintEngineState::QRasterPaintEngineState()
       
   652 {
       
   653     stroker = 0;
       
   654 
       
   655     fillFlags = 0;
       
   656     strokeFlags = 0;
       
   657     pixmapFlags = 0;
       
   658 
       
   659     intOpacity = 256;
       
   660 
       
   661     txscale = 1.;
       
   662 
       
   663     flags.fast_pen = true;
       
   664     flags.antialiased = false;
       
   665     flags.bilinear = false;
       
   666     flags.fast_text = true;
       
   667     flags.int_xform = true;
       
   668     flags.tx_noshear = true;
       
   669     flags.fast_images = true;
       
   670 
       
   671     clip = 0;
       
   672     flags.has_clip_ownership = false;
       
   673 
       
   674     dirty = 0;
       
   675 }
       
   676 
       
   677 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
       
   678     : QPainterState(s)
       
   679 {
       
   680     stroker = s.stroker;
       
   681 
       
   682     lastBrush = s.lastBrush;
       
   683     brushData = s.brushData;
       
   684     brushData.tempImage = 0;
       
   685 
       
   686     lastPen = s.lastPen;
       
   687     penData = s.penData;
       
   688     penData.tempImage = 0;
       
   689 
       
   690     fillFlags = s.fillFlags;
       
   691     strokeFlags = s.strokeFlags;
       
   692     pixmapFlags = s.pixmapFlags;
       
   693 
       
   694     intOpacity = s.intOpacity;
       
   695 
       
   696     txscale = s.txscale;
       
   697 
       
   698     flag_bits = s.flag_bits;
       
   699 
       
   700     clip = s.clip;
       
   701     flags.has_clip_ownership = false;
       
   702 
       
   703     dirty = s.dirty;
       
   704 }
       
   705 
       
   706 /*!
       
   707     \internal
       
   708 */
       
   709 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
       
   710 {
       
   711     QRasterPaintEngineState *s;
       
   712     if (!orig)
       
   713         s = new QRasterPaintEngineState();
       
   714     else
       
   715         s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
       
   716 
       
   717     return s;
       
   718 }
       
   719 
       
   720 /*!
       
   721     \internal
       
   722 */
       
   723 void QRasterPaintEngine::setState(QPainterState *s)
       
   724 {
       
   725     Q_D(QRasterPaintEngine);
       
   726     QPaintEngineEx::setState(s);
       
   727     d->rasterBuffer->compositionMode = s->composition_mode;
       
   728 }
       
   729 
       
   730 /*!
       
   731     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
       
   732     \internal
       
   733 */
       
   734 
       
   735 /*!
       
   736     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
       
   737     \internal
       
   738 */
       
   739 
       
   740 /*!
       
   741     \internal
       
   742 */
       
   743 void QRasterPaintEngine::penChanged()
       
   744 {
       
   745 #ifdef QT_DEBUG_DRAW
       
   746     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
       
   747 #endif
       
   748     QRasterPaintEngineState *s = state();
       
   749     s->strokeFlags |= DirtyPen;
       
   750     s->dirty |= DirtyPen;
       
   751 }
       
   752 
       
   753 /*!
       
   754     \internal
       
   755 */
       
   756 void QRasterPaintEngine::updatePen(const QPen &pen)
       
   757 {
       
   758     Q_D(QRasterPaintEngine);
       
   759     QRasterPaintEngineState *s = state();
       
   760 #ifdef QT_DEBUG_DRAW
       
   761     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
       
   762 #endif
       
   763 
       
   764     Qt::PenStyle pen_style = qpen_style(pen);
       
   765 
       
   766     s->lastPen = pen;
       
   767     s->strokeFlags = 0;
       
   768 
       
   769     s->penData.clip = d->clip();
       
   770     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
       
   771 
       
   772     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
       
   773         || pen.brush().transform().type() >= QTransform::TxNone) {
       
   774         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
       
   775     }
       
   776 
       
   777     // Slightly ugly handling of an uncommon case... We need to change
       
   778     // the pen because it is reused in draw_midpoint to decide dashed
       
   779     // or non-dashed.
       
   780     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
       
   781         pen_style = Qt::SolidLine;
       
   782         s->lastPen.setStyle(Qt::SolidLine);
       
   783     }
       
   784 
       
   785     d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
       
   786     d->basicStroker.setCapStyle(qpen_capStyle(pen));
       
   787     d->basicStroker.setMiterLimit(pen.miterLimit());
       
   788 
       
   789     qreal penWidth = qpen_widthf(pen);
       
   790     if (penWidth == 0)
       
   791         d->basicStroker.setStrokeWidth(1);
       
   792     else
       
   793         d->basicStroker.setStrokeWidth(penWidth);
       
   794 
       
   795     if(pen_style == Qt::SolidLine) {
       
   796         s->stroker = &d->basicStroker;
       
   797     } else if (pen_style != Qt::NoPen) {
       
   798         if (!d->dashStroker)
       
   799             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
       
   800         if (pen.isCosmetic()) {
       
   801             d->dashStroker->setClipRect(d->deviceRect);
       
   802         } else {
       
   803             // ### I've seen this inverted devrect multiple places now...
       
   804             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
       
   805             d->dashStroker->setClipRect(clipRect);
       
   806         }
       
   807         d->dashStroker->setDashPattern(pen.dashPattern());
       
   808         d->dashStroker->setDashOffset(pen.dashOffset());
       
   809         s->stroker = d->dashStroker.data();
       
   810     } else {
       
   811         s->stroker = 0;
       
   812     }
       
   813 
       
   814     s->flags.fast_pen = pen_style > Qt::NoPen
       
   815                   && s->penData.blend
       
   816                   && !s->flags.antialiased
       
   817                   && (penWidth == 0 || (penWidth <= 1
       
   818                                         && (s->matrix.type() <= QTransform::TxTranslate
       
   819                                             || pen.isCosmetic())));
       
   820 
       
   821     ensureState(); // needed because of tx_noshear...
       
   822     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
       
   823 
       
   824     s->strokeFlags = 0;
       
   825 }
       
   826 
       
   827 
       
   828 
       
   829 /*!
       
   830     \internal
       
   831 */
       
   832 void QRasterPaintEngine::brushOriginChanged()
       
   833 {
       
   834     QRasterPaintEngineState *s = state();
       
   835 #ifdef QT_DEBUG_DRAW
       
   836     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
       
   837 #endif
       
   838 
       
   839     s->fillFlags |= DirtyBrushOrigin;
       
   840 }
       
   841 
       
   842 
       
   843 /*!
       
   844     \internal
       
   845 */
       
   846 void QRasterPaintEngine::brushChanged()
       
   847 {
       
   848     QRasterPaintEngineState *s = state();
       
   849 #ifdef QT_DEBUG_DRAW
       
   850     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
       
   851 #endif
       
   852     s->fillFlags |= DirtyBrush;
       
   853 }
       
   854 
       
   855 
       
   856 
       
   857 
       
   858 /*!
       
   859     \internal
       
   860 */
       
   861 void QRasterPaintEngine::updateBrush(const QBrush &brush)
       
   862 {
       
   863 #ifdef QT_DEBUG_DRAW
       
   864     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
       
   865 #endif
       
   866     Q_D(QRasterPaintEngine);
       
   867     QRasterPaintEngineState *s = state();
       
   868     // must set clip prior to setup, as setup uses it...
       
   869     s->brushData.clip = d->clip();
       
   870     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
       
   871     if (s->fillFlags & DirtyTransform
       
   872         || brush.transform().type() >= QTransform::TxNone)
       
   873         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
       
   874     s->lastBrush = brush;
       
   875     s->fillFlags = 0;
       
   876 }
       
   877 
       
   878 void QRasterPaintEngine::updateOutlineMapper()
       
   879 {
       
   880     Q_D(QRasterPaintEngine);
       
   881     d->outlineMapper->setMatrix(state()->matrix);
       
   882 }
       
   883 
       
   884 void QRasterPaintEngine::updateState()
       
   885 {
       
   886     QRasterPaintEngineState *s = state();
       
   887 
       
   888     if (s->dirty & DirtyTransform)
       
   889         updateMatrix(s->matrix);
       
   890 
       
   891     if (s->dirty & (DirtyPen|DirtyCompositionMode)) {
       
   892         const QPainter::CompositionMode mode = s->composition_mode;
       
   893         s->flags.fast_text = (s->penData.type == QSpanData::Solid)
       
   894                        && (mode == QPainter::CompositionMode_Source
       
   895                            || (mode == QPainter::CompositionMode_SourceOver
       
   896                                && qAlpha(s->penData.solid.color) == 255));
       
   897     }
       
   898 
       
   899     s->dirty = 0;
       
   900 }
       
   901 
       
   902 
       
   903 /*!
       
   904     \internal
       
   905 */
       
   906 void QRasterPaintEngine::opacityChanged()
       
   907 {
       
   908     QRasterPaintEngineState *s = state();
       
   909 
       
   910 #ifdef QT_DEBUG_DRAW
       
   911     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
       
   912 #endif
       
   913 
       
   914     s->fillFlags |= DirtyOpacity;
       
   915     s->strokeFlags |= DirtyOpacity;
       
   916     s->pixmapFlags |= DirtyOpacity;
       
   917     s->intOpacity = (int) (s->opacity * 256);
       
   918 }
       
   919 
       
   920 /*!
       
   921     \internal
       
   922 */
       
   923 void QRasterPaintEngine::compositionModeChanged()
       
   924 {
       
   925     Q_D(QRasterPaintEngine);
       
   926     QRasterPaintEngineState *s = state();
       
   927 
       
   928 #ifdef QT_DEBUG_DRAW
       
   929     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
       
   930 #endif
       
   931 
       
   932     s->fillFlags |= DirtyCompositionMode;
       
   933     s->dirty |= DirtyCompositionMode;
       
   934 
       
   935     s->strokeFlags |= DirtyCompositionMode;
       
   936     d->rasterBuffer->compositionMode = s->composition_mode;
       
   937 
       
   938     d->recalculateFastImages();
       
   939 }
       
   940 
       
   941 /*!
       
   942     \internal
       
   943 */
       
   944 void QRasterPaintEngine::renderHintsChanged()
       
   945 {
       
   946     QRasterPaintEngineState *s = state();
       
   947 
       
   948 #ifdef QT_DEBUG_DRAW
       
   949     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
       
   950 #endif
       
   951 
       
   952     bool was_aa = s->flags.antialiased;
       
   953     bool was_bilinear = s->flags.bilinear;
       
   954 
       
   955     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
       
   956     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
       
   957 
       
   958     if (was_aa != s->flags.antialiased)
       
   959         s->strokeFlags |= DirtyHints;
       
   960 
       
   961     if (was_bilinear != s->flags.bilinear) {
       
   962         s->strokeFlags |= DirtyPen;
       
   963         s->fillFlags |= DirtyBrush;
       
   964     }
       
   965 
       
   966     Q_D(QRasterPaintEngine);
       
   967     d->recalculateFastImages();
       
   968 }
       
   969 
       
   970 /*!
       
   971     \internal
       
   972 */
       
   973 void QRasterPaintEngine::transformChanged()
       
   974 {
       
   975     QRasterPaintEngineState *s = state();
       
   976 
       
   977 #ifdef QT_DEBUG_DRAW
       
   978     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
       
   979 #endif
       
   980 
       
   981     s->fillFlags |= DirtyTransform;
       
   982     s->strokeFlags |= DirtyTransform;
       
   983 
       
   984     s->dirty |= DirtyTransform;
       
   985 
       
   986     Q_D(QRasterPaintEngine);
       
   987     d->recalculateFastImages();
       
   988 }
       
   989 
       
   990 /*!
       
   991     \internal
       
   992 */
       
   993 void QRasterPaintEngine::clipEnabledChanged()
       
   994 {
       
   995     QRasterPaintEngineState *s = state();
       
   996 
       
   997 #ifdef QT_DEBUG_DRAW
       
   998     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
       
   999 #endif
       
  1000 
       
  1001     if (s->clip) {
       
  1002         s->clip->enabled = s->clipEnabled;
       
  1003         s->fillFlags |= DirtyClipEnabled;
       
  1004         s->strokeFlags |= DirtyClipEnabled;
       
  1005         s->pixmapFlags |= DirtyClipEnabled;
       
  1006     }
       
  1007 }
       
  1008 
       
  1009 #ifdef Q_WS_QWS
       
  1010 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
       
  1011 {
       
  1012     rasterBuffer->prepare(device);
       
  1013 }
       
  1014 #endif
       
  1015 
       
  1016 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
       
  1017                                           const QImage &img,
       
  1018                                           SrcOverBlendFunc func,
       
  1019                                           const QRect &clip,
       
  1020                                           int alpha,
       
  1021                                           const QRect &sr)
       
  1022 {
       
  1023     if (alpha == 0 || !clip.isValid())
       
  1024         return;
       
  1025 
       
  1026     Q_ASSERT(img.depth() >= 8);
       
  1027 
       
  1028     int srcBPL = img.bytesPerLine();
       
  1029     const uchar *srcBits = img.bits();
       
  1030     int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
       
  1031     int iw = img.width();
       
  1032     int ih = img.height();
       
  1033 
       
  1034     if (!sr.isEmpty()) {
       
  1035         iw = sr.width();
       
  1036         ih = sr.height();
       
  1037         // Adjust the image according to the source offset...
       
  1038         srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
       
  1039     }
       
  1040 
       
  1041     // adapt the x parameters
       
  1042     int x = qRound(pt.x());
       
  1043     int cx1 = clip.x();
       
  1044     int cx2 = clip.x() + clip.width();
       
  1045     if (x < cx1) {
       
  1046         int d = cx1 - x;
       
  1047         srcBits += srcSize * d;
       
  1048         iw -= d;
       
  1049         x = cx1;
       
  1050     }
       
  1051     if (x + iw > cx2) {
       
  1052         int d = x + iw - cx2;
       
  1053         iw -= d;
       
  1054     }
       
  1055     if (iw <= 0)
       
  1056         return;
       
  1057 
       
  1058     // adapt the y paremeters...
       
  1059     int cy1 = clip.y();
       
  1060     int cy2 = clip.y() + clip.height();
       
  1061     int y = qRound(pt.y());
       
  1062     if (y < cy1) {
       
  1063         int d = cy1 - y;
       
  1064         srcBits += srcBPL * d;
       
  1065         ih -= d;
       
  1066         y = cy1;
       
  1067     }
       
  1068     if (y + ih > cy2) {
       
  1069         int d = y + ih - cy2;
       
  1070         ih -= d;
       
  1071     }
       
  1072     if (ih <= 0)
       
  1073         return;
       
  1074 
       
  1075     // call the blend function...
       
  1076     int dstSize = rasterBuffer->bytesPerPixel();
       
  1077     int dstBPL = rasterBuffer->bytesPerLine();
       
  1078     func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
       
  1079          srcBits, srcBPL,
       
  1080          iw, ih,
       
  1081          alpha);
       
  1082 }
       
  1083 
       
  1084 
       
  1085 void QRasterPaintEnginePrivate::systemStateChanged()
       
  1086 {
       
  1087     QRect clipRect(0, 0,
       
  1088             qMin(QT_RASTER_COORD_LIMIT, device->width()),
       
  1089             qMin(QT_RASTER_COORD_LIMIT, device->height()));
       
  1090 
       
  1091     if (!systemClip.isEmpty()) {
       
  1092         QRegion clippedDeviceRgn = systemClip & clipRect;
       
  1093         deviceRect = clippedDeviceRgn.boundingRect();
       
  1094         baseClip->setClipRegion(clippedDeviceRgn);
       
  1095     } else {
       
  1096         deviceRect = clipRect;
       
  1097         baseClip->setClipRect(deviceRect);
       
  1098     }
       
  1099 #ifdef QT_DEBUG_DRAW
       
  1100     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
       
  1101 #endif
       
  1102 
       
  1103     exDeviceRect = deviceRect;
       
  1104 
       
  1105     Q_Q(QRasterPaintEngine);
       
  1106     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
       
  1107     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
       
  1108     q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
       
  1109 }
       
  1110 
       
  1111 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
       
  1112 {
       
  1113     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
       
  1114         return;
       
  1115 
       
  1116     Q_Q(QRasterPaintEngine);
       
  1117     bool bilinear = q->state()->flags.bilinear;
       
  1118 
       
  1119     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimise
       
  1120         spanData->setupMatrix(b.transform() * m, bilinear);
       
  1121     } else {
       
  1122         if (m.type() <= QTransform::TxTranslate) {
       
  1123             // specialize setupMatrix for translation matrices
       
  1124             // to avoid needless matrix inversion
       
  1125             spanData->m11 = 1;
       
  1126             spanData->m12 = 0;
       
  1127             spanData->m13 = 0;
       
  1128             spanData->m21 = 0;
       
  1129             spanData->m22 = 1;
       
  1130             spanData->m23 = 0;
       
  1131             spanData->m33 = 1;
       
  1132             spanData->dx = -m.dx();
       
  1133             spanData->dy = -m.dy();
       
  1134             spanData->txop = m.type();
       
  1135             spanData->bilinear = bilinear;
       
  1136             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
       
  1137             spanData->adjustSpanMethods();
       
  1138         } else {
       
  1139             spanData->setupMatrix(m, bilinear);
       
  1140         }
       
  1141     }
       
  1142 }
       
  1143 
       
  1144 // #define QT_CLIPPING_RATIOS
       
  1145 
       
  1146 #ifdef QT_CLIPPING_RATIOS
       
  1147 int rectClips;
       
  1148 int regionClips;
       
  1149 int totalClips;
       
  1150 
       
  1151 static void checkClipRatios(QRasterPaintEnginePrivate *d)
       
  1152 {
       
  1153     if (d->clip()->hasRectClip)
       
  1154         rectClips++;
       
  1155     if (d->clip()->hasRegionClip)
       
  1156         regionClips++;
       
  1157     totalClips++;
       
  1158 
       
  1159     if ((totalClips % 5000) == 0) {
       
  1160         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
       
  1161                rectClips * 100.0 / (qreal) totalClips,
       
  1162                regionClips * 100.0 / (qreal) totalClips,
       
  1163                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
       
  1164         totalClips = 0;
       
  1165         rectClips = 0;
       
  1166         regionClips = 0;
       
  1167     }
       
  1168 
       
  1169 }
       
  1170 #endif
       
  1171 
       
  1172 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
       
  1173 {
       
  1174     if (s->flags.has_clip_ownership)
       
  1175         delete s->clip;
       
  1176     s->clip = 0;
       
  1177     s->flags.has_clip_ownership = false;
       
  1178 }
       
  1179 
       
  1180 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
       
  1181 {
       
  1182     s->fillFlags |= QPaintEngine::DirtyClipPath;
       
  1183     s->strokeFlags |= QPaintEngine::DirtyClipPath;
       
  1184     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
       
  1185 
       
  1186     d->solid_color_filler.clip = d->clip();
       
  1187     d->solid_color_filler.adjustSpanMethods();
       
  1188 
       
  1189 #ifdef QT_DEBUG_DRAW
       
  1190     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
       
  1191 #endif
       
  1192 
       
  1193 }
       
  1194 
       
  1195 
       
  1196 /*!
       
  1197     \internal
       
  1198 */
       
  1199 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
       
  1200 {
       
  1201 #ifdef QT_DEBUG_DRAW
       
  1202     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
       
  1203 
       
  1204     if (path.elements()) {
       
  1205         for (int i=0; i<path.elementCount(); ++i) {
       
  1206             qDebug() << " - " << path.elements()[i]
       
  1207                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
       
  1208         }
       
  1209     } else {
       
  1210         for (int i=0; i<path.elementCount(); ++i) {
       
  1211             qDebug() << " ---- "
       
  1212                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
       
  1213         }
       
  1214     }
       
  1215 #endif
       
  1216 
       
  1217     Q_D(QRasterPaintEngine);
       
  1218     QRasterPaintEngineState *s = state();
       
  1219 
       
  1220     const qreal *points = path.points();
       
  1221     const QPainterPath::ElementType *types = path.elements();
       
  1222 
       
  1223     // There are some cases that are not supported by clip(QRect)
       
  1224     if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
       
  1225                                 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
       
  1226         if (s->matrix.type() <= QTransform::TxTranslate
       
  1227             && ((path.shape() == QVectorPath::RectangleHint)
       
  1228                 || (isRect(points, path.elementCount())
       
  1229                     && (!types || (types[0] == QPainterPath::MoveToElement
       
  1230                                    && types[1] == QPainterPath::LineToElement
       
  1231                                    && types[2] == QPainterPath::LineToElement
       
  1232                                    && types[3] == QPainterPath::LineToElement))))) {
       
  1233 #ifdef QT_DEBUG_DRAW
       
  1234             qDebug() << " --- optimizing vector clip to rect clip...";
       
  1235 #endif
       
  1236 
       
  1237             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
       
  1238             clip(r.toRect(), op);
       
  1239             return;
       
  1240         }
       
  1241     }
       
  1242 
       
  1243     if (op == Qt::NoClip) {
       
  1244         qrasterpaintengine_state_setNoClip(s);
       
  1245 
       
  1246     } else {
       
  1247         QClipData *base = d->baseClip.data();
       
  1248 
       
  1249         // Intersect with current clip when available...
       
  1250         if (op == Qt::IntersectClip && s->clip)
       
  1251             base = s->clip;
       
  1252 
       
  1253         // We always intersect, except when there is nothing to
       
  1254         // intersect with, in which case we simplify the operation to
       
  1255         // a replace...
       
  1256         Qt::ClipOperation isectOp = Qt::IntersectClip;
       
  1257         if (base == 0)
       
  1258             isectOp = Qt::ReplaceClip;
       
  1259 
       
  1260         QClipData *newClip = new QClipData(d->rasterBuffer->height());
       
  1261         newClip->initialize();
       
  1262         ClipData clipData = { base, newClip, isectOp };
       
  1263         ensureOutlineMapper();
       
  1264         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
       
  1265 
       
  1266         newClip->fixup();
       
  1267 
       
  1268         if (op == Qt::UniteClip) {
       
  1269             // merge clips
       
  1270             QClipData *result = new QClipData(d->rasterBuffer->height());
       
  1271             QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
       
  1272             qt_merge_clip(current, newClip, result);
       
  1273             result->fixup();
       
  1274             delete newClip;
       
  1275             if (!s->clip)
       
  1276                 delete current;
       
  1277             newClip = result;
       
  1278         }
       
  1279 
       
  1280         if (s->flags.has_clip_ownership)
       
  1281             delete s->clip;
       
  1282 
       
  1283         s->clip = newClip;
       
  1284         s->flags.has_clip_ownership = true;
       
  1285     }
       
  1286     qrasterpaintengine_dirty_clip(d, s);
       
  1287 }
       
  1288 
       
  1289 
       
  1290 
       
  1291 /*!
       
  1292     \internal
       
  1293 */
       
  1294 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
       
  1295 {
       
  1296 #ifdef QT_DEBUG_DRAW
       
  1297     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
       
  1298 #endif
       
  1299 
       
  1300     Q_D(QRasterPaintEngine);
       
  1301     QRasterPaintEngineState *s = state();
       
  1302 
       
  1303     if (op == Qt::NoClip) {
       
  1304         qrasterpaintengine_state_setNoClip(s);
       
  1305 
       
  1306     } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
       
  1307         QPaintEngineEx::clip(rect, op);
       
  1308         return;
       
  1309 
       
  1310     } else if (op == Qt::ReplaceClip || s->clip == 0) {
       
  1311 
       
  1312         // No current clip, hence we intersect with sysclip and be
       
  1313         // done with it...
       
  1314         QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
       
  1315         QRegion clipRegion = systemClip();
       
  1316         QClipData *clip = new QClipData(d->rasterBuffer->height());
       
  1317 
       
  1318         if (clipRegion.isEmpty())
       
  1319             clip->setClipRect(clipRect);
       
  1320         else
       
  1321             clip->setClipRegion(clipRegion & clipRect);
       
  1322 
       
  1323         if (s->flags.has_clip_ownership)
       
  1324             delete s->clip;
       
  1325 
       
  1326         s->clip = clip;
       
  1327         s->clip->enabled = true;
       
  1328         s->flags.has_clip_ownership = true;
       
  1329 
       
  1330     } else { // intersect clip with current clip
       
  1331         QClipData *base = s->clip;
       
  1332 
       
  1333         Q_ASSERT(base);
       
  1334         if (base->hasRectClip || base->hasRegionClip) {
       
  1335             QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
       
  1336             if (!s->flags.has_clip_ownership) {
       
  1337                 s->clip = new QClipData(d->rasterBuffer->height());
       
  1338                 s->flags.has_clip_ownership = true;
       
  1339             }
       
  1340             if (base->hasRectClip)
       
  1341                 s->clip->setClipRect(base->clipRect & clipRect);
       
  1342             else
       
  1343                 s->clip->setClipRegion(base->clipRegion & clipRect);
       
  1344             s->clip->enabled = true;
       
  1345         } else {
       
  1346             QPaintEngineEx::clip(rect, op);
       
  1347             return;
       
  1348         }
       
  1349     }
       
  1350     qrasterpaintengine_dirty_clip(d, s);
       
  1351 }
       
  1352 
       
  1353 
       
  1354 /*!
       
  1355     \internal
       
  1356 */
       
  1357 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
       
  1358 {
       
  1359 #ifdef QT_DEBUG_DRAW
       
  1360     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
       
  1361 #endif
       
  1362 
       
  1363     Q_D(QRasterPaintEngine);
       
  1364 
       
  1365     if (region.numRects() == 1) {
       
  1366         clip(region.boundingRect(), op);
       
  1367         return;
       
  1368     }
       
  1369 
       
  1370     QRasterPaintEngineState *s = state();
       
  1371     const QClipData *clip = d->clip();
       
  1372     const QClipData *baseClip = d->baseClip.data();
       
  1373 
       
  1374     if (op == Qt::NoClip) {
       
  1375         qrasterpaintengine_state_setNoClip(s);
       
  1376     } else if (s->matrix.type() > QTransform::TxScale
       
  1377                || op == Qt::UniteClip
       
  1378                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
       
  1379                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
       
  1380         QPaintEngineEx::clip(region, op);
       
  1381     } else {
       
  1382         const QClipData *curClip;
       
  1383         QClipData *newClip;
       
  1384 
       
  1385         if (op == Qt::IntersectClip)
       
  1386             curClip = clip;
       
  1387         else
       
  1388             curClip = baseClip;
       
  1389 
       
  1390         if (s->flags.has_clip_ownership) {
       
  1391             newClip = s->clip;
       
  1392             Q_ASSERT(newClip);
       
  1393         } else {
       
  1394             newClip = new QClipData(d->rasterBuffer->height());
       
  1395             s->clip = newClip;
       
  1396             s->flags.has_clip_ownership = true;
       
  1397         }
       
  1398 
       
  1399         QRegion r = s->matrix.map(region);
       
  1400         if (curClip->hasRectClip)
       
  1401             newClip->setClipRegion(r & curClip->clipRect);
       
  1402         else if (curClip->hasRegionClip)
       
  1403             newClip->setClipRegion(r & curClip->clipRegion);
       
  1404 
       
  1405         qrasterpaintengine_dirty_clip(d, s);
       
  1406     }
       
  1407 }
       
  1408 
       
  1409 /*!
       
  1410     \internal
       
  1411 */
       
  1412 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
       
  1413 {
       
  1414 #ifdef QT_DEBUG_DRAW
       
  1415     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
       
  1416 #endif
       
  1417 
       
  1418     if (!fillData->blend)
       
  1419         return;
       
  1420 
       
  1421     Q_D(QRasterPaintEngine);
       
  1422 
       
  1423     const QRectF controlPointRect = path.controlPointRect();
       
  1424 
       
  1425     QRasterPaintEngineState *s = state();
       
  1426     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
       
  1427     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
       
  1428     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
       
  1429                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
       
  1430                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
       
  1431                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
       
  1432 
       
  1433     if (!s->flags.antialiased && !do_clip) {
       
  1434         d->initializeRasterizer(fillData);
       
  1435         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
       
  1436         return;
       
  1437     }
       
  1438 
       
  1439     ensureOutlineMapper();
       
  1440     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
       
  1441 }
       
  1442 
       
  1443 static void fillRect_normalized(const QRect &r, QSpanData *data,
       
  1444                                 QRasterPaintEnginePrivate *pe)
       
  1445 {
       
  1446     int x1, x2, y1, y2;
       
  1447 
       
  1448     bool rectClipped = true;
       
  1449 
       
  1450     if (data->clip) {
       
  1451         x1 = qMax(r.x(), data->clip->xmin);
       
  1452         x2 = qMin(r.x() + r.width(), data->clip->xmax);
       
  1453         y1 = qMax(r.y(), data->clip->ymin);
       
  1454         y2 = qMin(r.y() + r.height(), data->clip->ymax);
       
  1455         rectClipped = data->clip->hasRectClip;
       
  1456 
       
  1457     } else if (pe) {
       
  1458         x1 = qMax(r.x(), pe->deviceRect.x());
       
  1459         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
       
  1460         y1 = qMax(r.y(), pe->deviceRect.y());
       
  1461         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
       
  1462     } else {
       
  1463         x1 = qMax(r.x(), 0);
       
  1464         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
       
  1465         y1 = qMax(r.y(), 0);
       
  1466         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
       
  1467     }
       
  1468 
       
  1469     if (x2 <= x1 || y2 <= y1)
       
  1470         return;
       
  1471 
       
  1472     const int width = x2 - x1;
       
  1473     const int height = y2 - y1;
       
  1474 
       
  1475     bool isUnclipped = rectClipped
       
  1476                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
       
  1477 
       
  1478     if (pe && isUnclipped) {
       
  1479         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
       
  1480 
       
  1481         if (data->fillRect && (mode == QPainter::CompositionMode_Source
       
  1482                                || (mode == QPainter::CompositionMode_SourceOver
       
  1483                                    && qAlpha(data->solid.color) == 255)))
       
  1484         {
       
  1485             data->fillRect(data->rasterBuffer, x1, y1, width, height,
       
  1486                            data->solid.color);
       
  1487             return;
       
  1488         }
       
  1489     }
       
  1490 
       
  1491     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
       
  1492 
       
  1493     const int nspans = 256;
       
  1494     QT_FT_Span spans[nspans];
       
  1495 
       
  1496     Q_ASSERT(data->blend);
       
  1497     int y = y1;
       
  1498     while (y < y2) {
       
  1499         int n = qMin(nspans, y2 - y);
       
  1500         int i = 0;
       
  1501         while (i < n) {
       
  1502             spans[i].x = x1;
       
  1503             spans[i].len = width;
       
  1504             spans[i].y = y + i;
       
  1505             spans[i].coverage = 255;
       
  1506             ++i;
       
  1507         }
       
  1508 
       
  1509         blend(n, spans, data);
       
  1510         y += n;
       
  1511     }
       
  1512 }
       
  1513 
       
  1514 /*!
       
  1515     \reimp
       
  1516 */
       
  1517 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
       
  1518 {
       
  1519 #ifdef QT_DEBUG_DRAW
       
  1520     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
       
  1521 #endif
       
  1522     Q_D(QRasterPaintEngine);
       
  1523     QRasterPaintEngineState *s = state();
       
  1524 
       
  1525     // Fill
       
  1526     ensureBrush();
       
  1527     if (s->brushData.blend) {
       
  1528         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
       
  1529             const QRect *r = rects;
       
  1530             const QRect *lastRect = rects + rectCount;
       
  1531 
       
  1532             int offset_x = int(s->matrix.dx());
       
  1533             int offset_y = int(s->matrix.dy());
       
  1534             while (r < lastRect) {
       
  1535                 QRect rect = r->normalized();
       
  1536                 QRect rr = rect.translated(offset_x, offset_y);
       
  1537                 fillRect_normalized(rr, &s->brushData, d);
       
  1538                 ++r;
       
  1539             }
       
  1540         } else {
       
  1541             QRectVectorPath path;
       
  1542             for (int i=0; i<rectCount; ++i) {
       
  1543                 path.set(rects[i]);
       
  1544                 fill(path, s->brush);
       
  1545             }
       
  1546         }
       
  1547     }
       
  1548 
       
  1549     ensurePen();
       
  1550     if (s->penData.blend) {
       
  1551         if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
       
  1552             const QRect *r = rects;
       
  1553             const QRect *lastRect = rects + rectCount;
       
  1554             while (r < lastRect) {
       
  1555                 int left = r->x();
       
  1556                 int right = r->x() + r->width();
       
  1557                 int top = r->y();
       
  1558                 int bottom = r->y() + r->height();
       
  1559 
       
  1560 #ifdef Q_WS_MAC
       
  1561                 int pts[] = { top, left,
       
  1562                               top, right,
       
  1563                               bottom, right,
       
  1564                               bottom, left };
       
  1565 #else
       
  1566                 int pts[] = { left, top,
       
  1567                               right, top,
       
  1568                               right, bottom,
       
  1569                               left, bottom };
       
  1570 #endif
       
  1571 
       
  1572                 strokePolygonCosmetic((QPoint *) pts, 4, WindingMode);
       
  1573                 ++r;
       
  1574             }
       
  1575         } else {
       
  1576             QRectVectorPath path;
       
  1577             for (int i = 0; i < rectCount; ++i) {
       
  1578                 path.set(rects[i]);
       
  1579                 stroke(path, s->pen);
       
  1580             }
       
  1581         }
       
  1582     }
       
  1583 }
       
  1584 
       
  1585 /*!
       
  1586     \reimp
       
  1587 */
       
  1588 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
       
  1589 {
       
  1590 #ifdef QT_DEBUG_DRAW
       
  1591     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
       
  1592 #endif
       
  1593 #ifdef QT_FAST_SPANS
       
  1594     Q_D(QRasterPaintEngine);
       
  1595     QRasterPaintEngineState *s = state();
       
  1596 
       
  1597     ensureState();
       
  1598 
       
  1599     if (s->flags.tx_noshear) {
       
  1600         ensureBrush();
       
  1601         if (s->brushData.blend) {
       
  1602             d->initializeRasterizer(&s->brushData);
       
  1603             for (int i = 0; i < rectCount; ++i) {
       
  1604                 const QRectF &rect = rects[i].normalized();
       
  1605                 if (rect.isEmpty())
       
  1606                     continue;
       
  1607                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
       
  1608                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
       
  1609                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
       
  1610             }
       
  1611         }
       
  1612 
       
  1613         ensurePen();
       
  1614         if (s->penData.blend) {
       
  1615             qreal width = s->pen.isCosmetic()
       
  1616                           ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF())
       
  1617                           : s->lastPen.widthF() * s->txscale;
       
  1618 
       
  1619             if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
       
  1620                 for (int i = 0; i < rectCount; ++i) {
       
  1621                     const QRectF &r = rects[i];
       
  1622                     qreal left = r.x();
       
  1623                     qreal right = r.x() + r.width();
       
  1624                     qreal top = r.y();
       
  1625                     qreal bottom = r.y() + r.height();
       
  1626                     qreal pts[] = { left, top,
       
  1627                                     right, top,
       
  1628                                     right, bottom,
       
  1629                                     left, bottom };
       
  1630                     strokePolygonCosmetic((QPointF *) pts, 4, WindingMode);
       
  1631                 }
       
  1632             } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) {
       
  1633                 d->initializeRasterizer(&s->penData);
       
  1634 
       
  1635                 for (int i = 0; i < rectCount; ++i) {
       
  1636                     const QRectF &rect = rects[i].normalized();
       
  1637                     if (rect.isEmpty()) {
       
  1638                         qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() };
       
  1639                         QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint);
       
  1640                         QPaintEngineEx::stroke(vp, s->lastPen);
       
  1641                     } else {
       
  1642                         const QPointF tl = s->matrix.map(rect.topLeft());
       
  1643                         const QPointF tr = s->matrix.map(rect.topRight());
       
  1644                         const QPointF bl = s->matrix.map(rect.bottomLeft());
       
  1645                         const QPointF br = s->matrix.map(rect.bottomRight());
       
  1646                         const qreal w = width / (rect.width() * s->txscale);
       
  1647                         const qreal h = width / (rect.height() * s->txscale);
       
  1648                         d->rasterizer->rasterizeLine(tl, tr, w); // top
       
  1649                         d->rasterizer->rasterizeLine(bl, br, w); // bottom
       
  1650                         d->rasterizer->rasterizeLine(bl, tl, h); // left
       
  1651                         d->rasterizer->rasterizeLine(br, tr, h); // right
       
  1652                     }
       
  1653                 }
       
  1654             } else {
       
  1655                 for (int i = 0; i < rectCount; ++i) {
       
  1656                     const QRectF &r = rects[i];
       
  1657                     qreal left = r.x();
       
  1658                     qreal right = r.x() + r.width();
       
  1659                     qreal top = r.y();
       
  1660                     qreal bottom = r.y() + r.height();
       
  1661                     qreal pts[] = { left, top,
       
  1662                                     right, top,
       
  1663                                     right, bottom,
       
  1664                                     left, bottom,
       
  1665                                     left, top };
       
  1666                     QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
       
  1667                     QPaintEngineEx::stroke(vp, s->lastPen);
       
  1668                 }
       
  1669             }
       
  1670         }
       
  1671 
       
  1672         return;
       
  1673     }
       
  1674 #endif // QT_FAST_SPANS
       
  1675     QPaintEngineEx::drawRects(rects, rectCount);
       
  1676 }
       
  1677 
       
  1678 
       
  1679 /*!
       
  1680     \internal
       
  1681 */
       
  1682 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
       
  1683 {
       
  1684     QRasterPaintEngineState *s = state();
       
  1685     ensurePen(pen);
       
  1686     if (!s->penData.blend)
       
  1687         return;
       
  1688 
       
  1689     if (s->flags.fast_pen && path.shape() <= QVectorPath::NonCurvedShapeHint
       
  1690         && s->lastPen.brush().isOpaque()) {
       
  1691         int count = path.elementCount();
       
  1692         QPointF *points = (QPointF *) path.points();
       
  1693         const QPainterPath::ElementType *types = path.elements();
       
  1694         if (types) {
       
  1695             int first = 0;
       
  1696             int last;
       
  1697             while (first < count) {
       
  1698                 while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
       
  1699                 last = first + 1;
       
  1700                 while (last < count && types[last] == QPainterPath::LineToElement) ++last;
       
  1701                 strokePolygonCosmetic(points + first, last - first,
       
  1702                                       path.hasImplicitClose() && last == count // only close last one..
       
  1703                                       ? WindingMode
       
  1704                                       : PolylineMode);
       
  1705                 first = last;
       
  1706             }
       
  1707         } else {
       
  1708             strokePolygonCosmetic(points, count,
       
  1709                                   path.hasImplicitClose()
       
  1710                                   ? WindingMode
       
  1711                                   : PolylineMode);
       
  1712         }
       
  1713 
       
  1714     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
       
  1715         qreal width = s->lastPen.isCosmetic()
       
  1716                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
       
  1717                       : qpen_widthf(s->lastPen) * s->txscale;
       
  1718         int dashIndex = 0;
       
  1719         qreal dashOffset = s->lastPen.dashOffset();
       
  1720         bool inDash = true;
       
  1721         qreal patternLength = 0;
       
  1722         const QVector<qreal> pattern = s->lastPen.dashPattern();
       
  1723         for (int i = 0; i < pattern.size(); ++i)
       
  1724             patternLength += pattern.at(i);
       
  1725 
       
  1726         if (patternLength > 0) {
       
  1727             int n = qFloor(dashOffset / patternLength);
       
  1728             dashOffset -= n * patternLength;
       
  1729             while (dashOffset > pattern.at(dashIndex)) {
       
  1730                 dashOffset -= pattern.at(dashIndex);
       
  1731                 dashIndex = (dashIndex + 1) % pattern.size();
       
  1732                 inDash = !inDash;
       
  1733             }
       
  1734         }
       
  1735 
       
  1736         Q_D(QRasterPaintEngine);
       
  1737         d->initializeRasterizer(&s->penData);
       
  1738         int lineCount = path.elementCount() / 2;
       
  1739         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
       
  1740 
       
  1741         for (int i = 0; i < lineCount; ++i) {
       
  1742             if (path.shape() == QVectorPath::LinesHint)
       
  1743                 dashOffset = s->lastPen.dashOffset();
       
  1744             if (lines[i].p1() == lines[i].p2()) {
       
  1745                 if (s->lastPen.capStyle() != Qt::FlatCap) {
       
  1746                     QPointF p = lines[i].p1();
       
  1747                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
       
  1748                                                        QPointF(p.x() + width*0.5, p.y())));
       
  1749                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
       
  1750                 }
       
  1751                 continue;
       
  1752             }
       
  1753 
       
  1754             const QLineF line = s->matrix.map(lines[i]);
       
  1755             if (qpen_style(s->lastPen) == Qt::SolidLine) {
       
  1756                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
       
  1757                                             width / line.length(),
       
  1758                                             s->lastPen.capStyle() == Qt::SquareCap);
       
  1759             } else {
       
  1760                 d->rasterizeLine_dashed(line, width,
       
  1761                                         &dashIndex, &dashOffset, &inDash);
       
  1762             }
       
  1763         }
       
  1764     }
       
  1765     else
       
  1766         QPaintEngineEx::stroke(path, pen);
       
  1767 }
       
  1768 
       
  1769 static inline QRect toNormalizedFillRect(const QRectF &rect)
       
  1770 {
       
  1771     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
       
  1772     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
       
  1773     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
       
  1774     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
       
  1775 
       
  1776     if (x2 < x1)
       
  1777         qSwap(x1, x2);
       
  1778     if (y2 < y1)
       
  1779         qSwap(y1, y2);
       
  1780 
       
  1781     return QRect(x1, y1, x2 - x1, y2 - y1);
       
  1782 }
       
  1783 
       
  1784 /*!
       
  1785     \internal
       
  1786 */
       
  1787 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
       
  1788 {
       
  1789     if (path.isEmpty())
       
  1790         return;
       
  1791 #ifdef QT_DEBUG_DRAW
       
  1792     QRectF rf = path.controlPointRect();
       
  1793     qDebug() << "QRasterPaintEngine::fill(): "
       
  1794              << "size=" << path.elementCount()
       
  1795              << ", hints=" << hex << path.hints()
       
  1796              << rf << brush;
       
  1797 #endif
       
  1798 
       
  1799     Q_D(QRasterPaintEngine);
       
  1800     QRasterPaintEngineState *s = state();
       
  1801 
       
  1802     ensureBrush(brush);
       
  1803     if (!s->brushData.blend)
       
  1804         return;
       
  1805 
       
  1806     if (path.shape() == QVectorPath::RectangleHint) {
       
  1807         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
       
  1808             const qreal *p = path.points();
       
  1809             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
       
  1810             QPointF br = QPointF(p[4], p[5]) * s->matrix;
       
  1811             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
       
  1812             return;
       
  1813         }
       
  1814         ensureState();
       
  1815         if (s->flags.tx_noshear) {
       
  1816             d->initializeRasterizer(&s->brushData);
       
  1817             // ### Is normalizing really nessesary here?
       
  1818             const qreal *p = path.points();
       
  1819             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
       
  1820             if (!r.isEmpty()) {
       
  1821                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
       
  1822                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
       
  1823                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
       
  1824             }
       
  1825             return;
       
  1826         }
       
  1827     }
       
  1828 
       
  1829     if (path.shape() == QVectorPath::EllipseHint) {
       
  1830         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
       
  1831             const qreal *p = path.points();
       
  1832             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
       
  1833             QPointF br = QPointF(p[4], p[5]) * s->matrix;
       
  1834             QRectF r = s->matrix.mapRect(QRectF(tl, br));
       
  1835 
       
  1836             ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
       
  1837             ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
       
  1838             const QRect brect = QRect(int(r.x()), int(r.y()),
       
  1839                                       int_dim(r.x(), r.width()),
       
  1840                                       int_dim(r.y(), r.height()));
       
  1841             if (brect == r) {
       
  1842                 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
       
  1843                                        &s->penData, &s->brushData);
       
  1844                 return;
       
  1845             }
       
  1846         }
       
  1847     }
       
  1848 
       
  1849     // ### Optimize for non transformed ellipses and rectangles...
       
  1850     QRectF cpRect = path.controlPointRect();
       
  1851     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
       
  1852     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
       
  1853 
       
  1854         // ### Falcon
       
  1855 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
       
  1856 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
       
  1857 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
       
  1858 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
       
  1859 
       
  1860         // ### Falonc: implement....
       
  1861 //         if (!s->flags.antialiased && !do_clip) {
       
  1862 //             d->initializeRasterizer(&s->brushData);
       
  1863 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
       
  1864 //             return;
       
  1865 //         }
       
  1866 
       
  1867     ensureOutlineMapper();
       
  1868     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
       
  1869 }
       
  1870 
       
  1871 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
       
  1872 {
       
  1873     Q_D(QRasterPaintEngine);
       
  1874     QRasterPaintEngineState *s = state();
       
  1875 
       
  1876     if (!s->flags.antialiased) {
       
  1877         uint txop = s->matrix.type();
       
  1878         if (txop == QTransform::TxNone) {
       
  1879             fillRect_normalized(toNormalizedFillRect(r), data, d);
       
  1880             return;
       
  1881         } else if (txop == QTransform::TxTranslate) {
       
  1882             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
       
  1883             fillRect_normalized(rr, data, d);
       
  1884             return;
       
  1885         } else if (txop == QTransform::TxScale) {
       
  1886             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
       
  1887             fillRect_normalized(rr, data, d);
       
  1888             return;
       
  1889         }
       
  1890     }
       
  1891     ensureState();
       
  1892     if (s->flags.tx_noshear) {
       
  1893         d->initializeRasterizer(data);
       
  1894         QRectF nr = r.normalized();
       
  1895         if (!nr.isEmpty()) {
       
  1896             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
       
  1897             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
       
  1898             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
       
  1899         }
       
  1900         return;
       
  1901     }
       
  1902 
       
  1903     QPainterPath path;
       
  1904     path.addRect(r);
       
  1905     ensureOutlineMapper();
       
  1906     fillPath(path, data);
       
  1907 }
       
  1908 
       
  1909 /*!
       
  1910     \reimp
       
  1911 */
       
  1912 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
       
  1913 {
       
  1914 #ifdef QT_DEBUG_DRAW
       
  1915     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
       
  1916 #endif
       
  1917     QRasterPaintEngineState *s = state();
       
  1918 
       
  1919     ensureBrush(brush);
       
  1920     if (!s->brushData.blend)
       
  1921         return;
       
  1922 
       
  1923     fillRect(r, &s->brushData);
       
  1924 }
       
  1925 
       
  1926 /*!
       
  1927     \reimp
       
  1928 */
       
  1929 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
       
  1930 {
       
  1931 #ifdef QT_DEBUG_DRAW
       
  1932     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
       
  1933 #endif
       
  1934     Q_D(QRasterPaintEngine);
       
  1935     QRasterPaintEngineState *s = state();
       
  1936 
       
  1937     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
       
  1938     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
       
  1939         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
       
  1940         return;
       
  1941     }
       
  1942     d->solid_color_filler.clip = d->clip();
       
  1943     d->solid_color_filler.adjustSpanMethods();
       
  1944     fillRect(r, &d->solid_color_filler);
       
  1945 }
       
  1946 
       
  1947 static inline bool isAbove(const QPointF *a, const QPointF *b)
       
  1948 {
       
  1949     return a->y() < b->y();
       
  1950 }
       
  1951 
       
  1952 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
       
  1953 {
       
  1954     Q_ASSERT(upper);
       
  1955     Q_ASSERT(lower);
       
  1956 
       
  1957     Q_ASSERT(pointCount >= 2);
       
  1958 
       
  1959     QVector<const QPointF *> sorted;
       
  1960     sorted.reserve(pointCount);
       
  1961 
       
  1962     upper->reserve(pointCount * 3 / 4);
       
  1963     lower->reserve(pointCount * 3 / 4);
       
  1964 
       
  1965     for (int i = 0; i < pointCount; ++i)
       
  1966         sorted << points + i;
       
  1967 
       
  1968     qSort(sorted.begin(), sorted.end(), isAbove);
       
  1969 
       
  1970     qreal splitY = sorted.at(sorted.size() / 2)->y();
       
  1971 
       
  1972     const QPointF *end = points + pointCount;
       
  1973     const QPointF *last = end - 1;
       
  1974 
       
  1975     QVector<QPointF> *bin[2] = { upper, lower };
       
  1976 
       
  1977     for (const QPointF *p = points; p < end; ++p) {
       
  1978         int side = p->y() < splitY;
       
  1979         int lastSide = last->y() < splitY;
       
  1980 
       
  1981         if (side != lastSide) {
       
  1982             if (qFuzzyCompare(p->y(), splitY)) {
       
  1983                 bin[!side]->append(*p);
       
  1984             } else if (qFuzzyCompare(last->y(), splitY)) {
       
  1985                 bin[side]->append(*last);
       
  1986             } else {
       
  1987                 QPointF delta = *p - *last;
       
  1988                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
       
  1989 
       
  1990                 bin[0]->append(intersection);
       
  1991                 bin[1]->append(intersection);
       
  1992             }
       
  1993         }
       
  1994 
       
  1995         bin[side]->append(*p);
       
  1996 
       
  1997         last = p;
       
  1998     }
       
  1999 
       
  2000     // give up if we couldn't reduce the point count
       
  2001     return upper->size() < pointCount && lower->size() < pointCount;
       
  2002 }
       
  2003 
       
  2004 /*!
       
  2005   \internal
       
  2006  */
       
  2007 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
  2008 {
       
  2009     Q_D(QRasterPaintEngine);
       
  2010     QRasterPaintEngineState *s = state();
       
  2011 
       
  2012     const int maxPoints = 0xffff;
       
  2013 
       
  2014     // max amount of points that raster engine can reliably handle
       
  2015     if (pointCount > maxPoints) {
       
  2016         QVector<QPointF> upper, lower;
       
  2017 
       
  2018         if (splitPolygon(points, pointCount, &upper, &lower)) {
       
  2019             fillPolygon(upper.constData(), upper.size(), mode);
       
  2020             fillPolygon(lower.constData(), lower.size(), mode);
       
  2021         } else
       
  2022             qWarning("Polygon too complex for filling.");
       
  2023 
       
  2024         return;
       
  2025     }
       
  2026 
       
  2027     // Compose polygon fill..,
       
  2028     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
       
  2029     ensureOutlineMapper();
       
  2030     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
       
  2031 
       
  2032     // scanconvert.
       
  2033     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
       
  2034                                               &s->brushData);
       
  2035     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
       
  2036 }
       
  2037 
       
  2038 /*!
       
  2039     \reimp
       
  2040 */
       
  2041 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
  2042 {
       
  2043     Q_D(QRasterPaintEngine);
       
  2044     QRasterPaintEngineState *s = state();
       
  2045 
       
  2046 #ifdef QT_DEBUG_DRAW
       
  2047     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
       
  2048     for (int i=0; i<pointCount; ++i)
       
  2049         qDebug() << "   - " << points[i];
       
  2050 #endif
       
  2051     Q_ASSERT(pointCount >= 2);
       
  2052 
       
  2053     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
       
  2054         QRectF r(points[0], points[2]);
       
  2055         drawRects(&r, 1);
       
  2056         return;
       
  2057     }
       
  2058 
       
  2059     ensurePen();
       
  2060     ensureBrush();
       
  2061     if (mode != PolylineMode) {
       
  2062         // Do the fill...
       
  2063         if (s->brushData.blend) {
       
  2064             d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
       
  2065             fillPolygon(points, pointCount, mode);
       
  2066             d->outlineMapper->setCoordinateRounding(false);
       
  2067         }
       
  2068     }
       
  2069 
       
  2070     // Do the outline...
       
  2071     if (s->penData.blend) {
       
  2072         if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
       
  2073             strokePolygonCosmetic(points, pointCount, mode);
       
  2074         else {
       
  2075             QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
       
  2076             QPaintEngineEx::stroke(vp, s->lastPen);
       
  2077         }
       
  2078     }
       
  2079 }
       
  2080 
       
  2081 /*!
       
  2082     \reimp
       
  2083 */
       
  2084 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
       
  2085 {
       
  2086     Q_D(QRasterPaintEngine);
       
  2087     QRasterPaintEngineState *s = state();
       
  2088 
       
  2089 #ifdef QT_DEBUG_DRAW
       
  2090     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
       
  2091     for (int i=0; i<pointCount; ++i)
       
  2092         qDebug() << "   - " << points[i];
       
  2093 #endif
       
  2094     Q_ASSERT(pointCount >= 2);
       
  2095     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
       
  2096         QRect r(points[0].x(),
       
  2097                 points[0].y(),
       
  2098                 points[2].x() - points[0].x(),
       
  2099                 points[2].y() - points[0].y());
       
  2100         drawRects(&r, 1);
       
  2101         return;
       
  2102     }
       
  2103 
       
  2104     ensureState();
       
  2105     ensurePen();
       
  2106     if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) {
       
  2107         // this calls the float version
       
  2108         QPaintEngineEx::drawPolygon(points, pointCount, mode);
       
  2109         return;
       
  2110     }
       
  2111 
       
  2112     // Do the fill
       
  2113     if (mode != PolylineMode) {
       
  2114         ensureBrush();
       
  2115         if (s->brushData.blend) {
       
  2116             // Compose polygon fill..,
       
  2117             ensureOutlineMapper();
       
  2118             d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
       
  2119             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
       
  2120             d->outlineMapper->moveTo(*points);
       
  2121             const QPoint *p = points;
       
  2122             const QPoint *ep = points + pointCount - 1;
       
  2123             do {
       
  2124                 d->outlineMapper->lineTo(*(++p));
       
  2125             } while (p < ep);
       
  2126             d->outlineMapper->endOutline();
       
  2127 
       
  2128             // scanconvert.
       
  2129             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
       
  2130                                                       &s->brushData);
       
  2131             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
       
  2132             d->outlineMapper->setCoordinateRounding(false);
       
  2133         }
       
  2134     }
       
  2135 
       
  2136     // Do the outline...
       
  2137     if (s->penData.blend) {
       
  2138         if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
       
  2139             strokePolygonCosmetic(points, pointCount, mode);
       
  2140         else {
       
  2141             int count = pointCount * 2;
       
  2142             QVarLengthArray<qreal> fpoints(count);
       
  2143 #ifdef Q_WS_MAC
       
  2144             for (int i=0; i<count; i+=2) {
       
  2145                 fpoints[i] = ((int *) points)[i+1];
       
  2146                 fpoints[i+1] = ((int *) points)[i];
       
  2147             }
       
  2148 #else
       
  2149             for (int i=0; i<count; ++i)
       
  2150                 fpoints[i] = ((int *) points)[i];
       
  2151 #endif
       
  2152             QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
       
  2153             QPaintEngineEx::stroke(vp, s->lastPen);
       
  2154         }
       
  2155     }
       
  2156 }
       
  2157 
       
  2158 /*!
       
  2159     \internal
       
  2160 */
       
  2161 void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
  2162 {
       
  2163     Q_D(QRasterPaintEngine);
       
  2164     QRasterPaintEngineState *s = state();
       
  2165 
       
  2166     Q_ASSERT(s->penData.blend);
       
  2167     Q_ASSERT(s->flags.fast_pen);
       
  2168 
       
  2169     bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
       
  2170 
       
  2171     // Use fast path for 0 width /  trivial pens.
       
  2172     QIntRect devRect;
       
  2173     devRect.set(d->deviceRect);
       
  2174 
       
  2175     LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
       
  2176                                   ? LineDrawIncludeLastPixel
       
  2177                                   : LineDrawNormal);
       
  2178     int dashOffset = int(s->lastPen.dashOffset());
       
  2179 
       
  2180     const QPointF offs(aliasedCoordinateDelta, aliasedCoordinateDelta);
       
  2181 
       
  2182     // Draw all the line segments.
       
  2183     for (int i=1; i<pointCount; ++i) {
       
  2184 
       
  2185         QPointF lp1 = points[i-1] * s->matrix + offs;
       
  2186         QPointF lp2 = points[i] * s->matrix + offs;
       
  2187 
       
  2188         const QRectF brect(lp1, lp2);
       
  2189         ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2190         if (qpen_style(s->lastPen) == Qt::SolidLine) {
       
  2191             drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
       
  2192                                 qFloor(lp2.x()), qFloor(lp2.y()),
       
  2193                                 penBlend, &s->penData,
       
  2194                                 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2195                                 devRect);
       
  2196         } else {
       
  2197             drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
       
  2198                                        qFloor(lp2.x()), qFloor(lp2.y()),
       
  2199                                        &s->lastPen,
       
  2200                                        penBlend, &s->penData,
       
  2201                                        i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2202                                        devRect, &dashOffset);
       
  2203         }
       
  2204     }
       
  2205 
       
  2206     // Polygons are implicitly closed.
       
  2207     if (needs_closing) {
       
  2208         QPointF lp1 = points[pointCount-1] * s->matrix + offs;
       
  2209         QPointF lp2 = points[0] * s->matrix + offs;
       
  2210 
       
  2211         const QRectF brect(lp1, lp2);
       
  2212         ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2213         if (qpen_style(s->lastPen) == Qt::SolidLine) {
       
  2214             drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
       
  2215                                 qFloor(lp2.x()), qFloor(lp2.y()),
       
  2216                                 penBlend, &s->penData,
       
  2217                                 LineDrawIncludeLastPixel,
       
  2218                                 devRect);
       
  2219         } else {
       
  2220             drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
       
  2221                                        qFloor(lp2.x()), qFloor(lp2.y()),
       
  2222                                        &s->lastPen,
       
  2223                                        penBlend, &s->penData,
       
  2224                                        LineDrawIncludeLastPixel,
       
  2225                                        devRect, &dashOffset);
       
  2226         }
       
  2227     }
       
  2228 
       
  2229 }
       
  2230 
       
  2231 /*!
       
  2232     \internal
       
  2233 */
       
  2234 void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode)
       
  2235 {
       
  2236     Q_D(QRasterPaintEngine);
       
  2237     QRasterPaintEngineState *s = state();
       
  2238 
       
  2239     // We assert here because this function is called from drawRects
       
  2240     // and drawPolygon and they already do ensurePen(), so we skip that
       
  2241     // here to avoid duplicate checks..
       
  2242     Q_ASSERT(s->penData.blend);
       
  2243 
       
  2244     bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
       
  2245 
       
  2246     QIntRect devRect;
       
  2247     devRect.set(d->deviceRect);
       
  2248 
       
  2249     LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
       
  2250                                   ? LineDrawIncludeLastPixel
       
  2251                                   : LineDrawNormal);
       
  2252 
       
  2253     int m11 = int(s->matrix.m11());
       
  2254     int m22 = int(s->matrix.m22());
       
  2255     int dx = int(s->matrix.dx());
       
  2256     int dy = int(s->matrix.dy());
       
  2257     int m13 = int(s->matrix.m13());
       
  2258     int m23 = int(s->matrix.m23());
       
  2259     bool affine = !m13 && !m23;
       
  2260 
       
  2261     int dashOffset = int(s->lastPen.dashOffset());
       
  2262 
       
  2263     if (affine) {
       
  2264         // Draw all the line segments.
       
  2265         for (int i=1; i<pointCount; ++i) {
       
  2266             const QPoint lp1 = points[i-1] * s->matrix;
       
  2267             const QPoint lp2 = points[i] * s->matrix;
       
  2268             const QRect brect(lp1, lp2);
       
  2269             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2270 
       
  2271             if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  2272                 drawLine_midpoint_i(lp1.x(), lp1.y(),
       
  2273                                     lp2.x(), lp2.y(),
       
  2274                                     penBlend, &s->penData,
       
  2275                                     i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2276                                     devRect);
       
  2277             else
       
  2278                 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
       
  2279                                            lp2.x(), lp2.y(),
       
  2280                                            &s->lastPen,
       
  2281                                            penBlend, &s->penData,
       
  2282                                            i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2283                                            devRect, &dashOffset);
       
  2284 
       
  2285         }
       
  2286 
       
  2287         // Polygons are implicitly closed.
       
  2288         if (needs_closing) {
       
  2289             const QPoint lp1 = points[pointCount - 1] * s->matrix;
       
  2290             const QPoint lp2 = points[0] * s->matrix;
       
  2291             const QRect brect(lp1, lp2);
       
  2292             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2293 
       
  2294             if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  2295                 drawLine_midpoint_i(lp1.x(), lp1.y(),
       
  2296                                     lp2.x(), lp2.y(),
       
  2297                                     penBlend, &s->penData, LineDrawIncludeLastPixel,
       
  2298                                     devRect);
       
  2299             else
       
  2300                 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
       
  2301                                            lp2.x(), lp2.y(),
       
  2302                                            &s->lastPen,
       
  2303                                            penBlend, &s->penData, LineDrawIncludeLastPixel,
       
  2304                                            devRect, &dashOffset);
       
  2305         }
       
  2306     } else {
       
  2307         // Draw all the line segments.
       
  2308         for (int i=1; i<pointCount; ++i) {
       
  2309             int x1 = points[i-1].x() * m11 + dx;
       
  2310             int y1 = points[i-1].y() * m22 + dy;
       
  2311             qreal w = m13*points[i-1].x() + m23*points[i-1].y() + 1.;
       
  2312             w = 1/w;
       
  2313             x1 = int(x1*w);
       
  2314             y1 = int(y1*w);
       
  2315             int x2 = points[i].x() * m11 + dx;
       
  2316             int y2 = points[i].y() * m22 + dy;
       
  2317             w = m13*points[i].x() + m23*points[i].y() + 1.;
       
  2318             w = 1/w;
       
  2319             x2 = int(x2*w);
       
  2320             y2 = int(y2*w);
       
  2321 
       
  2322             const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
       
  2323             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2324             if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  2325                 drawLine_midpoint_i(x1, y1, x2, y2,
       
  2326                                     penBlend, &s->penData,
       
  2327                                     i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2328                                     devRect);
       
  2329             else
       
  2330                 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
       
  2331                                            &s->lastPen,
       
  2332                                            penBlend, &s->penData,
       
  2333                                            i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
       
  2334                                            devRect, &dashOffset);
       
  2335 
       
  2336         }
       
  2337 
       
  2338         int x1 = points[pointCount-1].x() * m11 + dx;
       
  2339         int y1 = points[pointCount-1].y() * m22 + dy;
       
  2340         qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.;
       
  2341         w = 1/w;
       
  2342         x1 = int(x1*w);
       
  2343         y1 = int(y1*w);
       
  2344         int x2 = points[0].x() * m11 + dx;
       
  2345         int y2 = points[0].y() * m22 + dy;
       
  2346         w = m13*points[0].x() + m23*points[0].y() + 1.;
       
  2347         w = 1/w;
       
  2348         x2 = int(x2 * w);
       
  2349         y2 = int(y2 * w);
       
  2350         // Polygons are implicitly closed.
       
  2351 
       
  2352         if (needs_closing) {
       
  2353             const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
       
  2354             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  2355             if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  2356                 drawLine_midpoint_i(x1, y1, x2, y2,
       
  2357                                     penBlend, &s->penData, LineDrawIncludeLastPixel,
       
  2358                                     devRect);
       
  2359             else
       
  2360                 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
       
  2361                                            &s->lastPen,
       
  2362                                            penBlend, &s->penData, LineDrawIncludeLastPixel,
       
  2363                                            devRect, &dashOffset);
       
  2364         }
       
  2365     }
       
  2366 }
       
  2367 
       
  2368 /*!
       
  2369     \internal
       
  2370 */
       
  2371 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
       
  2372 {
       
  2373 #ifdef QT_DEBUG_DRAW
       
  2374     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
       
  2375 #endif
       
  2376 
       
  2377     if (pixmap.data->classId() == QPixmapData::RasterClass) {
       
  2378         const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
       
  2379         if (image.depth() == 1) {
       
  2380             Q_D(QRasterPaintEngine);
       
  2381             QRasterPaintEngineState *s = state();
       
  2382             if (s->matrix.type() <= QTransform::TxTranslate) {
       
  2383                 ensurePen();
       
  2384                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
       
  2385             } else {
       
  2386                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
       
  2387             }
       
  2388         } else {
       
  2389             QRasterPaintEngine::drawImage(pos, image);
       
  2390         }
       
  2391     } else {
       
  2392         const QImage image = pixmap.toImage();
       
  2393         if (pixmap.depth() == 1) {
       
  2394             Q_D(QRasterPaintEngine);
       
  2395             QRasterPaintEngineState *s = state();
       
  2396             if (s->matrix.type() <= QTransform::TxTranslate) {
       
  2397                 ensurePen();
       
  2398                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
       
  2399             } else {
       
  2400                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
       
  2401             }
       
  2402         } else {
       
  2403             QRasterPaintEngine::drawImage(pos, image);
       
  2404         }
       
  2405     }
       
  2406 }
       
  2407 
       
  2408 /*!
       
  2409     \reimp
       
  2410 */
       
  2411 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
       
  2412 {
       
  2413 #ifdef QT_DEBUG_DRAW
       
  2414     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
       
  2415 #endif
       
  2416 
       
  2417     if (pixmap.data->classId() == QPixmapData::RasterClass) {
       
  2418         const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
       
  2419         if (image.depth() == 1) {
       
  2420             Q_D(QRasterPaintEngine);
       
  2421             QRasterPaintEngineState *s = state();
       
  2422             if (s->matrix.type() <= QTransform::TxTranslate
       
  2423                 && r.size() == sr.size()
       
  2424                 && r.size() == pixmap.size()) {
       
  2425                 ensurePen();
       
  2426                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
       
  2427                 return;
       
  2428             } else {
       
  2429                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
       
  2430             }
       
  2431         } else {
       
  2432             drawImage(r, image, sr);
       
  2433         }
       
  2434     } else {
       
  2435         const QImage image = pixmap.toImage();
       
  2436         if (image.depth() == 1) {
       
  2437             Q_D(QRasterPaintEngine);
       
  2438             QRasterPaintEngineState *s = state();
       
  2439             if (s->matrix.type() <= QTransform::TxTranslate
       
  2440                 && r.size() == sr.size()
       
  2441                 && r.size() == pixmap.size()) {
       
  2442                 ensurePen();
       
  2443                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
       
  2444                 return;
       
  2445             } else {
       
  2446                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
       
  2447             }
       
  2448         } else {
       
  2449             drawImage(r, image, sr);
       
  2450         }
       
  2451     }
       
  2452 }
       
  2453 
       
  2454 // assumes that rect has positive width and height
       
  2455 static inline const QRect toRect_normalized(const QRectF &rect)
       
  2456 {
       
  2457     const int x = qRound(rect.x());
       
  2458     const int y = qRound(rect.y());
       
  2459     const int w = int(rect.width() + qreal(0.5));
       
  2460     const int h = int(rect.height() + qreal(0.5));
       
  2461 
       
  2462     return QRect(x, y, w, h);
       
  2463 }
       
  2464 
       
  2465 static inline int fast_ceil_positive(const qreal &v)
       
  2466 {
       
  2467     const int iv = int(v);
       
  2468     if (v - iv == 0)
       
  2469         return iv;
       
  2470     else
       
  2471         return iv + 1;
       
  2472 }
       
  2473 
       
  2474 static inline const QRect toAlignedRect_positive(const QRectF &rect)
       
  2475 {
       
  2476     const int xmin = int(rect.x());
       
  2477     const int xmax = int(fast_ceil_positive(rect.right()));
       
  2478     const int ymin = int(rect.y());
       
  2479     const int ymax = int(fast_ceil_positive(rect.bottom()));
       
  2480     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
       
  2481 }
       
  2482 
       
  2483 /*!
       
  2484     \internal
       
  2485 */
       
  2486 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
       
  2487 {
       
  2488 #ifdef QT_DEBUG_DRAW
       
  2489     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
       
  2490 #endif
       
  2491 
       
  2492     Q_D(QRasterPaintEngine);
       
  2493     QRasterPaintEngineState *s = state();
       
  2494 
       
  2495     if (s->matrix.type() > QTransform::TxTranslate) {
       
  2496         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
       
  2497                   img,
       
  2498                   QRectF(0, 0, img.width(), img.height()));
       
  2499     } else {
       
  2500 
       
  2501         const QClipData *clip = d->clip();
       
  2502         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
       
  2503 
       
  2504         if (s->flags.fast_images) {
       
  2505             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
       
  2506             if (func) {
       
  2507                 if (!clip) {
       
  2508                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
       
  2509                     return;
       
  2510                 } else if (clip->hasRectClip) {
       
  2511                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
       
  2512                     return;
       
  2513                 }
       
  2514             }
       
  2515         }
       
  2516 
       
  2517 
       
  2518 
       
  2519         d->image_filler.clip = clip;
       
  2520         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
       
  2521         if (!d->image_filler.blend)
       
  2522             return;
       
  2523         d->image_filler.dx = -pt.x();
       
  2524         d->image_filler.dy = -pt.y();
       
  2525         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
       
  2526 
       
  2527         fillRect_normalized(rr, &d->image_filler, d);
       
  2528     }
       
  2529 
       
  2530 }
       
  2531 
       
  2532 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
       
  2533 {
       
  2534     return QRectF(r.topLeft() * t, r.bottomRight() * t);
       
  2535 }
       
  2536 
       
  2537 /*!
       
  2538     \reimp
       
  2539 */
       
  2540 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
       
  2541                                    Qt::ImageConversionFlags)
       
  2542 {
       
  2543 #ifdef QT_DEBUG_DRAW
       
  2544     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
       
  2545 #endif
       
  2546 
       
  2547     if (r.isEmpty())
       
  2548         return;
       
  2549 
       
  2550     Q_D(QRasterPaintEngine);
       
  2551     QRasterPaintEngineState *s = state();
       
  2552     int sr_l = qFloor(sr.left());
       
  2553     int sr_r = qCeil(sr.right()) - 1;
       
  2554     int sr_t = qFloor(sr.top());
       
  2555     int sr_b = qCeil(sr.bottom()) - 1;
       
  2556 
       
  2557     if (!s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
       
  2558         // as fillRect will apply the aliased coordinate delta we need to
       
  2559         // subtract it here as we don't use it for image drawing
       
  2560         QTransform old = s->matrix;
       
  2561         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
       
  2562 
       
  2563         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
       
  2564         QRgb color = img.pixel(sr_l, sr_t);
       
  2565         switch (img.format()) {
       
  2566         case QImage::Format_ARGB32_Premultiplied:
       
  2567         case QImage::Format_ARGB8565_Premultiplied:
       
  2568         case QImage::Format_ARGB6666_Premultiplied:
       
  2569         case QImage::Format_ARGB8555_Premultiplied:
       
  2570         case QImage::Format_ARGB4444_Premultiplied:
       
  2571             // Combine premultiplied color with the opacity set on the painter.
       
  2572             d->solid_color_filler.solid.color =
       
  2573                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
       
  2574                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
       
  2575             break;
       
  2576         default:
       
  2577             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
       
  2578             break;
       
  2579         }
       
  2580 
       
  2581         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
       
  2582             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
       
  2583             return;
       
  2584         }
       
  2585 
       
  2586         d->solid_color_filler.clip = d->clip();
       
  2587         d->solid_color_filler.adjustSpanMethods();
       
  2588         fillRect(r, &d->solid_color_filler);
       
  2589 
       
  2590         s->matrix = old;
       
  2591         return;
       
  2592     }
       
  2593 
       
  2594     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
       
  2595 
       
  2596     const QClipData *clip = d->clip();
       
  2597 
       
  2598     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
       
  2599 
       
  2600         if (s->flags.fast_images) {
       
  2601             if (s->matrix.type() > QTransform::TxScale) {
       
  2602                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
       
  2603                 if (func && (!clip || clip->hasRectClip)) {
       
  2604                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
       
  2605                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
       
  2606                          s->matrix, s->intOpacity);
       
  2607                     return;
       
  2608                 }
       
  2609             } else {
       
  2610                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
       
  2611                 if (func && (!clip || clip->hasRectClip)) {
       
  2612                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
       
  2613                          img.bits(), img.bytesPerLine(),
       
  2614                          qt_mapRect_non_normalizing(r, s->matrix), sr,
       
  2615                          !clip ? d->deviceRect : clip->clipRect,
       
  2616                          s->intOpacity);
       
  2617                     return;
       
  2618                 }
       
  2619             }
       
  2620         }
       
  2621 
       
  2622         QTransform copy = s->matrix;
       
  2623         copy.translate(r.x(), r.y());
       
  2624         if (stretch_sr)
       
  2625             copy.scale(r.width() / sr.width(), r.height() / sr.height());
       
  2626         copy.translate(-sr.x(), -sr.y());
       
  2627 
       
  2628         d->image_filler_xform.clip = clip;
       
  2629         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
       
  2630         if (!d->image_filler_xform.blend)
       
  2631             return;
       
  2632         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
       
  2633 
       
  2634         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
       
  2635             QRectF rr = s->matrix.mapRect(r);
       
  2636 
       
  2637             const int x1 = qRound(rr.x());
       
  2638             const int y1 = qRound(rr.y());
       
  2639             const int x2 = qRound(rr.right());
       
  2640             const int y2 = qRound(rr.bottom());
       
  2641 
       
  2642             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
       
  2643             return;
       
  2644         }
       
  2645 
       
  2646 #ifdef QT_FAST_SPANS
       
  2647         ensureState();
       
  2648         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
       
  2649             d->initializeRasterizer(&d->image_filler_xform);
       
  2650             d->rasterizer->setAntialiased(s->flags.antialiased);
       
  2651 
       
  2652             const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
       
  2653 
       
  2654             const QRectF &rect = r.normalized();
       
  2655             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
       
  2656             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
       
  2657 
       
  2658             if (s->flags.tx_noshear)
       
  2659                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
       
  2660             else
       
  2661                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
       
  2662             return;
       
  2663         }
       
  2664 #endif
       
  2665         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
       
  2666         QPainterPath path;
       
  2667         path.addRect(r);
       
  2668         QTransform m = s->matrix;
       
  2669         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
       
  2670                                m.m21(), m.m22(), m.m23(),
       
  2671                                m.m31() - offs, m.m32() - offs, m.m33());
       
  2672         fillPath(path, &d->image_filler_xform);
       
  2673         s->matrix = m;
       
  2674     } else {
       
  2675 
       
  2676         if (s->flags.fast_images) {
       
  2677             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
       
  2678             if (func) {
       
  2679                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
       
  2680                 if (!clip) {
       
  2681                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
       
  2682                     return;
       
  2683                 } else if (clip->hasRectClip) {
       
  2684                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
       
  2685                     return;
       
  2686                 }
       
  2687             }
       
  2688         }
       
  2689 
       
  2690         d->image_filler.clip = clip;
       
  2691         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
       
  2692         if (!d->image_filler.blend)
       
  2693             return;
       
  2694         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
       
  2695         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
       
  2696 
       
  2697         QRectF rr = r;
       
  2698         rr.translate(s->matrix.dx(), s->matrix.dy());
       
  2699 
       
  2700         const int x1 = qRound(rr.x());
       
  2701         const int y1 = qRound(rr.y());
       
  2702         const int x2 = qRound(rr.right());
       
  2703         const int y2 = qRound(rr.bottom());
       
  2704 
       
  2705         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
       
  2706     }
       
  2707 }
       
  2708 
       
  2709 /*!
       
  2710     \reimp
       
  2711 */
       
  2712 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
       
  2713 {
       
  2714 #ifdef QT_DEBUG_DRAW
       
  2715     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
       
  2716 #endif
       
  2717     Q_D(QRasterPaintEngine);
       
  2718     QRasterPaintEngineState *s = state();
       
  2719 
       
  2720     QImage image;
       
  2721 
       
  2722     if (pixmap.data->classId() == QPixmapData::RasterClass) {
       
  2723         image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
       
  2724     } else {
       
  2725         image = pixmap.toImage();
       
  2726     }
       
  2727 
       
  2728     if (image.depth() == 1)
       
  2729         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
       
  2730 
       
  2731     if (s->matrix.type() > QTransform::TxTranslate) {
       
  2732         QTransform copy = s->matrix;
       
  2733         copy.translate(r.x(), r.y());
       
  2734         copy.translate(-sr.x(), -sr.y());
       
  2735         d->image_filler_xform.clip = d->clip();
       
  2736         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
       
  2737         if (!d->image_filler_xform.blend)
       
  2738             return;
       
  2739         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
       
  2740 
       
  2741 #ifdef QT_FAST_SPANS
       
  2742         ensureState();
       
  2743         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
       
  2744             d->initializeRasterizer(&d->image_filler_xform);
       
  2745             d->rasterizer->setAntialiased(s->flags.antialiased);
       
  2746 
       
  2747             const QRectF &rect = r.normalized();
       
  2748             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
       
  2749             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
       
  2750             if (s->flags.tx_noshear)
       
  2751                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
       
  2752             else
       
  2753                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
       
  2754             return;
       
  2755         }
       
  2756 #endif
       
  2757         QPainterPath path;
       
  2758         path.addRect(r);
       
  2759         fillPath(path, &d->image_filler_xform);
       
  2760     } else {
       
  2761         d->image_filler.clip = d->clip();
       
  2762 
       
  2763         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
       
  2764         if (!d->image_filler.blend)
       
  2765             return;
       
  2766         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
       
  2767         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
       
  2768 
       
  2769         QRectF rr = r;
       
  2770         rr.translate(s->matrix.dx(), s->matrix.dy());
       
  2771         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
       
  2772     }
       
  2773 }
       
  2774 
       
  2775 
       
  2776 //QWS hack
       
  2777 static inline bool monoVal(const uchar* s, int x)
       
  2778 {
       
  2779     return  (s[x>>3] << (x&7)) & 0x80;
       
  2780 }
       
  2781 
       
  2782 /*!
       
  2783     \internal
       
  2784 */
       
  2785 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
       
  2786 {
       
  2787     Q_D(QRasterPaintEngine);
       
  2788     QRasterPaintEngineState *s = state();
       
  2789 
       
  2790     if (!s->penData.blend)
       
  2791         return;
       
  2792 
       
  2793     QRasterBuffer *rb = d->rasterBuffer.data();
       
  2794 
       
  2795     const QRect rect(rx, ry, w, h);
       
  2796     const QClipData *clip = d->clip();
       
  2797     bool unclipped = false;
       
  2798     if (clip) {
       
  2799         // inlined QRect::intersects
       
  2800         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
       
  2801                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
       
  2802 
       
  2803         if (clip->hasRectClip) {
       
  2804             unclipped = rx > clip->xmin
       
  2805                         && rx + w < clip->xmax
       
  2806                         && ry > clip->ymin
       
  2807                         && ry + h < clip->ymax;
       
  2808         }
       
  2809 
       
  2810         if (!intersects)
       
  2811             return;
       
  2812     } else {
       
  2813         // inlined QRect::intersects
       
  2814         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
       
  2815                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
       
  2816         if (!intersects)
       
  2817             return;
       
  2818 
       
  2819         // inlined QRect::contains
       
  2820         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
       
  2821                               && rect.top() >= 0 && rect.bottom() < rb->height();
       
  2822 
       
  2823         unclipped = contains && d->isUnclipped_normalized(rect);
       
  2824     }
       
  2825 
       
  2826     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
       
  2827     const uchar * scanline = static_cast<const uchar *>(src);
       
  2828 
       
  2829     if (s->flags.fast_text) {
       
  2830         if (unclipped) {
       
  2831             if (depth == 1) {
       
  2832                 if (s->penData.bitmapBlit) {
       
  2833                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
       
  2834                                           scanline, w, h, bpl);
       
  2835                     return;
       
  2836                 }
       
  2837             } else if (depth == 8) {
       
  2838                 if (s->penData.alphamapBlit) {
       
  2839                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
       
  2840                                             scanline, w, h, bpl, 0);
       
  2841                     return;
       
  2842                 }
       
  2843             } else if (depth == 32) {
       
  2844                 // (A)RGB Alpha mask where the alpha component is not used.
       
  2845                 if (s->penData.alphaRGBBlit) {
       
  2846                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
       
  2847                                             (const uint *) scanline, w, h, bpl / 4, 0);
       
  2848                     return;
       
  2849                 }
       
  2850             }
       
  2851         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
       
  2852             // (A)RGB Alpha mask where the alpha component is not used.
       
  2853             if (!clip) {
       
  2854                 int nx = qMax(0, rx);
       
  2855                 int ny = qMax(0, ry);
       
  2856 
       
  2857                 // Move scanline pointer to compensate for moved x and y
       
  2858                 int xdiff = nx - rx;
       
  2859                 int ydiff = ny - ry;
       
  2860                 scanline += ydiff * bpl;
       
  2861                 scanline += xdiff * (depth == 32 ? 4 : 1);
       
  2862 
       
  2863                 w -= xdiff;
       
  2864                 h -= ydiff;
       
  2865 
       
  2866                 if (nx + w > d->rasterBuffer->width())
       
  2867                     w = d->rasterBuffer->width() - nx;
       
  2868                 if (ny + h > d->rasterBuffer->height())
       
  2869                     h = d->rasterBuffer->height() - ny;
       
  2870 
       
  2871                 rx = nx;
       
  2872                 ry = ny;
       
  2873             }
       
  2874             if (depth == 8 && s->penData.alphamapBlit) {
       
  2875                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
       
  2876                                         scanline, w, h, bpl, clip);
       
  2877             } else if (depth == 32 && s->penData.alphaRGBBlit) {
       
  2878                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
       
  2879                                         (const uint *) scanline, w, h, bpl / 4, clip);
       
  2880             }
       
  2881             return;
       
  2882         }
       
  2883     }
       
  2884 
       
  2885     int x0 = 0;
       
  2886     if (rx < 0) {
       
  2887         x0 = -rx;
       
  2888         w -= x0;
       
  2889     }
       
  2890 
       
  2891     int y0 = 0;
       
  2892     if (ry < 0) {
       
  2893         y0 = -ry;
       
  2894         scanline += bpl * y0;
       
  2895         h -= y0;
       
  2896     }
       
  2897 
       
  2898     w = qMin(w, rb->width() - qMax(0, rx));
       
  2899     h = qMin(h, rb->height() - qMax(0, ry));
       
  2900 
       
  2901     if (w <= 0 || h <= 0)
       
  2902         return;
       
  2903 
       
  2904     const int NSPANS = 256;
       
  2905     QSpan spans[NSPANS];
       
  2906     int current = 0;
       
  2907 
       
  2908     const int x1 = x0 + w;
       
  2909     const int y1 = y0 + h;
       
  2910 
       
  2911     if (depth == 1) {
       
  2912         for (int y = y0; y < y1; ++y) {
       
  2913             for (int x = x0; x < x1; ) {
       
  2914                 if (!monoVal(scanline, x)) {
       
  2915                     ++x;
       
  2916                     continue;
       
  2917                 }
       
  2918 
       
  2919                 if (current == NSPANS) {
       
  2920                     blend(current, spans, &s->penData);
       
  2921                     current = 0;
       
  2922                 }
       
  2923                 spans[current].x = x + rx;
       
  2924                 spans[current].y = y + ry;
       
  2925                 spans[current].coverage = 255;
       
  2926                 int len = 1;
       
  2927                 ++x;
       
  2928                 // extend span until we find a different one.
       
  2929                 while (x < x1 && monoVal(scanline, x)) {
       
  2930                     ++x;
       
  2931                     ++len;
       
  2932                 }
       
  2933                 spans[current].len = len;
       
  2934                 ++current;
       
  2935             }
       
  2936             scanline += bpl;
       
  2937         }
       
  2938     } else if (depth == 8) {
       
  2939         for (int y = y0; y < y1; ++y) {
       
  2940             for (int x = x0; x < x1; ) {
       
  2941                 // Skip those with 0 coverage
       
  2942                 if (scanline[x] == 0) {
       
  2943                     ++x;
       
  2944                     continue;
       
  2945                 }
       
  2946 
       
  2947                 if (current == NSPANS) {
       
  2948                     blend(current, spans, &s->penData);
       
  2949                     current = 0;
       
  2950                 }
       
  2951                 int coverage = scanline[x];
       
  2952                 spans[current].x = x + rx;
       
  2953                 spans[current].y = y + ry;
       
  2954                 spans[current].coverage = coverage;
       
  2955                 int len = 1;
       
  2956                 ++x;
       
  2957 
       
  2958                 // extend span until we find a different one.
       
  2959                 while (x < x1 && scanline[x] == coverage) {
       
  2960                     ++x;
       
  2961                     ++len;
       
  2962                 }
       
  2963                 spans[current].len = len;
       
  2964                 ++current;
       
  2965             }
       
  2966             scanline += bpl;
       
  2967         }
       
  2968     } else { // 32-bit alpha...
       
  2969         uint *sl = (uint *) src;
       
  2970         for (int y = y0; y < y1; ++y) {
       
  2971             for (int x = x0; x < x1; ) {
       
  2972                 // Skip those with 0 coverage
       
  2973                 if ((sl[x] & 0x00ffffff) == 0) {
       
  2974                     ++x;
       
  2975                     continue;
       
  2976                 }
       
  2977 
       
  2978                 if (current == NSPANS) {
       
  2979                     blend(current, spans, &s->penData);
       
  2980                     current = 0;
       
  2981                 }
       
  2982                 uint rgbCoverage = sl[x];
       
  2983                 int coverage = qGreen(rgbCoverage);
       
  2984                 spans[current].x = x + rx;
       
  2985                 spans[current].y = y + ry;
       
  2986                 spans[current].coverage = coverage;
       
  2987                 int len = 1;
       
  2988                 ++x;
       
  2989 
       
  2990                 // extend span until we find a different one.
       
  2991                 while (x < x1 && sl[x] == rgbCoverage) {
       
  2992                     ++x;
       
  2993                     ++len;
       
  2994                 }
       
  2995                 spans[current].len = len;
       
  2996                 ++current;
       
  2997             }
       
  2998             sl += bpl / sizeof(uint);
       
  2999         }
       
  3000     }
       
  3001 //     qDebug() << "alphaPenBlt: num spans=" << current
       
  3002 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
       
  3003         // Call span func for current set of spans.
       
  3004     if (current != 0)
       
  3005         blend(current, spans, &s->penData);
       
  3006 }
       
  3007 
       
  3008 void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
       
  3009 {
       
  3010     Q_D(QRasterPaintEngine);
       
  3011     QRasterPaintEngineState *s = state();
       
  3012 
       
  3013     QVarLengthArray<QFixedPoint> positions;
       
  3014     QVarLengthArray<glyph_t> glyphs;
       
  3015     QTransform matrix = s->matrix;
       
  3016     matrix.translate(p.x(), p.y());
       
  3017     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  3018 
       
  3019     QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType;
       
  3020 
       
  3021     QImageTextureGlyphCache *cache =
       
  3022         (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
       
  3023     if (!cache) {
       
  3024         cache = new QImageTextureGlyphCache(glyphType, s->matrix);
       
  3025         ti.fontEngine->setGlyphCache(glyphType, cache);
       
  3026     }
       
  3027 
       
  3028     cache->populate(ti, glyphs, positions);
       
  3029 
       
  3030     const QImage &image = cache->image();
       
  3031     int bpl = image.bytesPerLine();
       
  3032 
       
  3033     int depth = image.depth();
       
  3034     int rightShift = 0;
       
  3035     int leftShift = 0;
       
  3036     if (depth == 32)
       
  3037         leftShift = 2; // multiply by 4
       
  3038     else if (depth == 1)
       
  3039         rightShift = 3; // divide by 8
       
  3040 
       
  3041     int margin = cache->glyphMargin();
       
  3042 
       
  3043     const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
       
  3044 
       
  3045     const uchar *bits = image.bits();
       
  3046     for (int i=0; i<glyphs.size(); ++i) {
       
  3047         const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
       
  3048         int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
       
  3049         int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
       
  3050 
       
  3051 //         printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
       
  3052 //                c.x, c.y,
       
  3053 //                c.w, c.h,
       
  3054 //                c.baseLineX, c.baseLineY,
       
  3055 //                glyphs[i],
       
  3056 //                x, y,
       
  3057 //                positions[i].x.toInt(), positions[i].y.toInt());
       
  3058 
       
  3059         alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
       
  3060     }
       
  3061 
       
  3062     return;
       
  3063 }
       
  3064 
       
  3065 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
       
  3066 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
       
  3067 {
       
  3068     Q_D(QRasterPaintEngine);
       
  3069     QRasterPaintEngineState *s = state();
       
  3070 
       
  3071     QFontEngine *fontEngine = ti.fontEngine;
       
  3072     if (fontEngine->type() != QFontEngine::S60FontEngine) {
       
  3073         QPaintEngineEx::drawTextItem(p, ti);
       
  3074         return;
       
  3075     }
       
  3076 
       
  3077     QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
       
  3078 
       
  3079     QVarLengthArray<QFixedPoint> positions;
       
  3080     QVarLengthArray<glyph_t> glyphs;
       
  3081     QTransform matrix = s->matrix;
       
  3082     matrix.translate(p.x(), p.y());
       
  3083     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  3084 
       
  3085     const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
       
  3086 
       
  3087     for (int i=0; i<glyphs.size(); ++i) {
       
  3088         TOpenFontCharMetrics tmetrics;
       
  3089         const TUint8 *glyphBitmapBytes;
       
  3090         TSize glyphBitmapSize;
       
  3091         fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
       
  3092         const glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]);
       
  3093         const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
       
  3094         const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
       
  3095 
       
  3096         alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
       
  3097     }
       
  3098 
       
  3099     return;
       
  3100 }
       
  3101 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
       
  3102 
       
  3103 /*!
       
  3104  * Returns true if the rectangle is completly within the current clip
       
  3105  * state of the paint engine.
       
  3106  */
       
  3107 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
       
  3108 {
       
  3109     const QClipData *cl = clip();
       
  3110     if (!cl) {
       
  3111         // inline contains() for performance (we know the rects are normalized)
       
  3112         const QRect &r1 = deviceRect;
       
  3113         return (r.left() >= r1.left() && r.right() <= r1.right()
       
  3114                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
       
  3115     }
       
  3116 
       
  3117 
       
  3118     if (cl->hasRectClip) {
       
  3119         // currently all painting functions clips to deviceRect internally
       
  3120         if (cl->clipRect == deviceRect)
       
  3121             return true;
       
  3122 
       
  3123         // inline contains() for performance (we know the rects are normalized)
       
  3124         const QRect &r1 = cl->clipRect;
       
  3125         return (r.left() >= r1.left() && r.right() <= r1.right()
       
  3126                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
       
  3127     } else {
       
  3128         return qt_region_strictContains(cl->clipRegion, r);
       
  3129     }
       
  3130 }
       
  3131 
       
  3132 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
       
  3133                                             int penWidth) const
       
  3134 {
       
  3135     Q_Q(const QRasterPaintEngine);
       
  3136     const QRasterPaintEngineState *s = q->state();
       
  3137     const QClipData *cl = clip();
       
  3138     if (!cl) {
       
  3139         QRect r = rect.normalized();
       
  3140         // inline contains() for performance (we know the rects are normalized)
       
  3141         const QRect &r1 = deviceRect;
       
  3142         return (r.left() >= r1.left() && r.right() <= r1.right()
       
  3143                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
       
  3144     }
       
  3145 
       
  3146 
       
  3147     // currently all painting functions that call this function clip to deviceRect internally
       
  3148     if (cl->hasRectClip && cl->clipRect == deviceRect)
       
  3149         return true;
       
  3150 
       
  3151     if (s->flags.antialiased)
       
  3152         ++penWidth;
       
  3153 
       
  3154     QRect r = rect.normalized();
       
  3155     if (penWidth > 0) {
       
  3156         r.setX(r.x() - penWidth);
       
  3157         r.setY(r.y() - penWidth);
       
  3158         r.setWidth(r.width() + 2 * penWidth);
       
  3159         r.setHeight(r.height() + 2 * penWidth);
       
  3160     }
       
  3161 
       
  3162     if (cl->hasRectClip) {
       
  3163         // inline contains() for performance (we know the rects are normalized)
       
  3164         const QRect &r1 = cl->clipRect;
       
  3165         return (r.left() >= r1.left() && r.right() <= r1.right()
       
  3166                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
       
  3167     } else {
       
  3168         return qt_region_strictContains(cl->clipRegion, r);
       
  3169     }
       
  3170 }
       
  3171 
       
  3172 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
       
  3173                                                    int penWidth) const
       
  3174 {
       
  3175     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
       
  3176 }
       
  3177 
       
  3178 inline ProcessSpans
       
  3179 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
       
  3180                                         const QSpanData *data) const
       
  3181 {
       
  3182     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
       
  3183 }
       
  3184 
       
  3185 inline ProcessSpans
       
  3186 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
       
  3187                                         const QSpanData *data) const
       
  3188 {
       
  3189     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
       
  3190 }
       
  3191 
       
  3192 inline ProcessSpans
       
  3193 QRasterPaintEnginePrivate::getPenFunc(const QRect &rect,
       
  3194                                       const QSpanData *data) const
       
  3195 {
       
  3196     Q_Q(const QRasterPaintEngine);
       
  3197     const QRasterPaintEngineState *s = q->state();
       
  3198 
       
  3199     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
       
  3200         return data->blend;
       
  3201     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->pen.widthF());
       
  3202     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
       
  3203 }
       
  3204 
       
  3205 inline ProcessSpans
       
  3206 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
       
  3207                                       const QSpanData *data) const
       
  3208 {
       
  3209     Q_Q(const QRasterPaintEngine);
       
  3210     const QRasterPaintEngineState *s = q->state();
       
  3211 
       
  3212     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
       
  3213         return data->blend;
       
  3214     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
       
  3215     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
       
  3216 }
       
  3217 
       
  3218 /*!
       
  3219     \reimp
       
  3220 */
       
  3221 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
       
  3222 {
       
  3223     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
       
  3224     QRasterPaintEngineState *s = state();
       
  3225 
       
  3226 #ifdef QT_DEBUG_DRAW
       
  3227     Q_D(QRasterPaintEngine);
       
  3228     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
       
  3229            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
       
  3230            d->glyphCacheType);
       
  3231 #endif
       
  3232 
       
  3233     ensurePen();
       
  3234     ensureState();
       
  3235 
       
  3236 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
       
  3237 
       
  3238     bool drawCached = true;
       
  3239 
       
  3240     if (s->matrix.type() >= QTransform::TxProject)
       
  3241         drawCached = false;
       
  3242 
       
  3243     // don't try to cache huge fonts
       
  3244     if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
       
  3245         drawCached = false;
       
  3246 
       
  3247     // ### Remove the TestFontEngine and Box engine crap, in these
       
  3248     // ### cases we should delegate painting to the font engine
       
  3249     // ### directly...
       
  3250 
       
  3251 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
       
  3252     QFontEngine::Type fontEngineType = ti.fontEngine->type();
       
  3253     // qDebug() << "type" << fontEngineType << s->matrix.type();
       
  3254     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
       
  3255         || (s->matrix.type() <= QTransform::TxTranslate
       
  3256             && (fontEngineType == QFontEngine::TestFontEngine
       
  3257                 || fontEngineType == QFontEngine::Box))) {
       
  3258             drawCached = false;
       
  3259     }
       
  3260 #else
       
  3261     if (s->matrix.type() > QTransform::TxTranslate)
       
  3262         drawCached = false;
       
  3263 #endif
       
  3264     if (drawCached) {
       
  3265         drawCachedGlyphs(p, ti);
       
  3266         return;
       
  3267     }
       
  3268 
       
  3269 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
       
  3270     if (s->matrix.type() <= QTransform::TxTranslate) {
       
  3271         drawGlyphsS60(p, ti);
       
  3272         return;
       
  3273     }
       
  3274 #else // Q_WS_WIN || Q_WS_MAC
       
  3275 
       
  3276     QFontEngine *fontEngine = ti.fontEngine;
       
  3277 
       
  3278 #if defined(Q_WS_QWS)
       
  3279     if (fontEngine->type() == QFontEngine::Box) {
       
  3280         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
       
  3281         return;
       
  3282     }
       
  3283 
       
  3284     if (s->matrix.type() < QTransform::TxScale
       
  3285         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
       
  3286             || (fontEngine->type() == QFontEngine::Proxy
       
  3287                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
       
  3288             )) {
       
  3289         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
       
  3290         return;
       
  3291     }
       
  3292 #endif // Q_WS_QWS
       
  3293 
       
  3294 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
       
  3295 
       
  3296 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
       
  3297     if (fontEngine->type() == QFontEngine::QPF2) {
       
  3298         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
       
  3299         if (renderingEngine)
       
  3300             fontEngine = renderingEngine;
       
  3301     }
       
  3302 #endif
       
  3303 
       
  3304     if (fontEngine->type() != QFontEngine::Freetype) {
       
  3305         QPaintEngineEx::drawTextItem(p, ti);
       
  3306         return;
       
  3307     }
       
  3308 
       
  3309     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
       
  3310 
       
  3311     QTransform matrix = s->matrix;
       
  3312     matrix.translate(p.x(), p.y());
       
  3313 
       
  3314     QVarLengthArray<QFixedPoint> positions;
       
  3315     QVarLengthArray<glyph_t> glyphs;
       
  3316     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  3317     if (glyphs.size() == 0)
       
  3318         return;
       
  3319 
       
  3320     // only use subpixel antialiasing when drawing to widgets
       
  3321     QFontEngineFT::GlyphFormat neededFormat =
       
  3322         painter()->device()->devType() == QInternal::Widget
       
  3323         ? fe->defaultGlyphFormat()
       
  3324         : QFontEngineFT::Format_A8;
       
  3325 
       
  3326     if (d_func()->mono_surface
       
  3327         || fe->isBitmapFont() // alphaPenBlt can handle mono, too
       
  3328         )
       
  3329         neededFormat = QFontEngineFT::Format_Mono;
       
  3330 
       
  3331     if (neededFormat == QFontEngineFT::Format_None)
       
  3332         neededFormat = QFontEngineFT::Format_A8;
       
  3333 
       
  3334     QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
       
  3335     if (s->matrix.type() >= QTransform::TxScale) {
       
  3336         if (s->matrix.isAffine())
       
  3337             gset = fe->loadTransformedGlyphSet(s->matrix);
       
  3338         else
       
  3339             gset = 0;
       
  3340 
       
  3341     }
       
  3342 
       
  3343     if (!gset || gset->outline_drawing
       
  3344         || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), neededFormat))
       
  3345     {
       
  3346         QPaintEngine::drawTextItem(p, ti);
       
  3347         return;
       
  3348     }
       
  3349 
       
  3350     QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
       
  3351     FT_Face lockedFace = 0;
       
  3352 
       
  3353     int depth;
       
  3354     switch (neededFormat) {
       
  3355     case QFontEngineFT::Format_Mono:
       
  3356         depth = 1;
       
  3357         break;
       
  3358     case QFontEngineFT::Format_A8:
       
  3359         depth = 8;
       
  3360         break;
       
  3361     case QFontEngineFT::Format_A32:
       
  3362         depth = 32;
       
  3363         break;
       
  3364     default:
       
  3365         Q_ASSERT(false);
       
  3366         depth = 0;
       
  3367     };
       
  3368 
       
  3369     for(int i = 0; i < glyphs.size(); i++) {
       
  3370         QFontEngineFT::Glyph *glyph = gset->glyph_data.value(glyphs[i]);
       
  3371 
       
  3372         if (!glyph || glyph->format != neededFormat) {
       
  3373             if (!lockedFace)
       
  3374                 lockedFace = fe->lockFace();
       
  3375             glyph = fe->loadGlyph(gset, glyphs[i], neededFormat);
       
  3376         }
       
  3377 
       
  3378         if (!glyph || !glyph->data)
       
  3379             continue;
       
  3380 
       
  3381         int pitch;
       
  3382         switch (neededFormat) {
       
  3383         case QFontEngineFT::Format_Mono:
       
  3384             pitch = ((glyph->width + 31) & ~31) >> 3;
       
  3385             break;
       
  3386         case QFontEngineFT::Format_A8:
       
  3387             pitch = (glyph->width + 3) & ~3;
       
  3388             break;
       
  3389         case QFontEngineFT::Format_A32:
       
  3390             pitch = glyph->width * 4;
       
  3391             break;
       
  3392         default:
       
  3393             Q_ASSERT(false);
       
  3394             pitch = 0;
       
  3395         };
       
  3396 
       
  3397         alphaPenBlt(glyph->data, pitch, depth,
       
  3398                     qFloor(positions[i].x + offs) + glyph->x,
       
  3399                     qFloor(positions[i].y + offs) - glyph->y,
       
  3400                     glyph->width, glyph->height);
       
  3401     }
       
  3402     if (lockedFace)
       
  3403         fe->unlockFace();
       
  3404     return;
       
  3405 
       
  3406 #endif
       
  3407 #endif
       
  3408 
       
  3409     QPaintEngineEx::drawTextItem(p, ti);
       
  3410 }
       
  3411 
       
  3412 /*!
       
  3413     \reimp
       
  3414 */
       
  3415 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
       
  3416 {
       
  3417     Q_D(QRasterPaintEngine);
       
  3418     QRasterPaintEngineState *s = state();
       
  3419 
       
  3420     ensurePen();
       
  3421     qreal pw = s->lastPen.widthF();
       
  3422     if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
       
  3423         QPaintEngineEx::drawPoints(points, pointCount);
       
  3424 
       
  3425     } else {
       
  3426         if (!s->penData.blend)
       
  3427             return;
       
  3428 
       
  3429         QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
       
  3430         QT_FT_Span span = { 0, 1, 0, 255 };
       
  3431         const QPointF *end = points + pointCount;
       
  3432         qreal trans_x, trans_y;
       
  3433         int x, y;
       
  3434         int left = d->deviceRect.x();
       
  3435         int right = left + d->deviceRect.width();
       
  3436         int top = d->deviceRect.y();
       
  3437         int bottom = top + d->deviceRect.height();
       
  3438         int count = 0;
       
  3439         while (points < end) {
       
  3440             s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
       
  3441             x = qFloor(trans_x);
       
  3442             y = qFloor(trans_y);
       
  3443             if (x >= left && x < right && y >= top && y < bottom) {
       
  3444                 if (count > 0) {
       
  3445                     const QT_FT_Span &last = array[count - 1];
       
  3446                     // spans must be sorted on y (primary) and x (secondary)
       
  3447                     if (y < last.y || (y == last.y && x < last.x)) {
       
  3448                         s->penData.blend(count, array.constData(), &s->penData);
       
  3449                         count = 0;
       
  3450                     }
       
  3451                 }
       
  3452 
       
  3453                 span.x = x;
       
  3454                 span.y = y;
       
  3455                 array[count++] = span;
       
  3456             }
       
  3457             ++points;
       
  3458         }
       
  3459 
       
  3460         if (count > 0)
       
  3461             s->penData.blend(count, array.constData(), &s->penData);
       
  3462     }
       
  3463 }
       
  3464 
       
  3465 
       
  3466 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
       
  3467 {
       
  3468     Q_D(QRasterPaintEngine);
       
  3469     QRasterPaintEngineState *s = state();
       
  3470 
       
  3471     ensurePen();
       
  3472     double pw = s->lastPen.widthF();
       
  3473     if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
       
  3474         QPaintEngineEx::drawPoints(points, pointCount);
       
  3475 
       
  3476     } else {
       
  3477         if (!s->penData.blend)
       
  3478             return;
       
  3479 
       
  3480         QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
       
  3481         QT_FT_Span span = { 0, 1, 0, 255 };
       
  3482         const QPoint *end = points + pointCount;
       
  3483         qreal trans_x, trans_y;
       
  3484         int x, y;
       
  3485         int left = d->deviceRect.x();
       
  3486         int right = left + d->deviceRect.width();
       
  3487         int top = d->deviceRect.y();
       
  3488         int bottom = top + d->deviceRect.height();
       
  3489         int count = 0;
       
  3490         while (points < end) {
       
  3491             s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
       
  3492             x = qFloor(trans_x);
       
  3493             y = qFloor(trans_y);
       
  3494             if (x >= left && x < right && y >= top && y < bottom) {
       
  3495                 if (count > 0) {
       
  3496                     const QT_FT_Span &last = array[count - 1];
       
  3497                     // spans must be sorted on y (primary) and x (secondary)
       
  3498                     if (y < last.y || (y == last.y && x < last.x)) {
       
  3499                         s->penData.blend(count, array.constData(), &s->penData);
       
  3500                         count = 0;
       
  3501                     }
       
  3502                 }
       
  3503 
       
  3504                 span.x = x;
       
  3505                 span.y = y;
       
  3506                 array[count++] = span;
       
  3507             }
       
  3508             ++points;
       
  3509         }
       
  3510 
       
  3511         if (count > 0)
       
  3512             s->penData.blend(count, array.constData(), &s->penData);
       
  3513     }
       
  3514 }
       
  3515 
       
  3516 /*!
       
  3517     \reimp
       
  3518 */
       
  3519 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
       
  3520 {
       
  3521 #ifdef QT_DEBUG_DRAW
       
  3522     qDebug() << " - QRasterPaintEngine::drawLine()";
       
  3523 #endif
       
  3524     Q_D(QRasterPaintEngine);
       
  3525     QRasterPaintEngineState *s = state();
       
  3526 
       
  3527     ensurePen();
       
  3528     if (s->flags.fast_pen) {
       
  3529         QIntRect bounds; bounds.set(d->deviceRect);
       
  3530         LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
       
  3531                             ? LineDrawNormal
       
  3532                             : LineDrawIncludeLastPixel;
       
  3533 
       
  3534         int m11 = int(s->matrix.m11());
       
  3535         int m22 = int(s->matrix.m22());
       
  3536         int dx = qFloor(s->matrix.dx() + aliasedCoordinateDelta);
       
  3537         int dy = qFloor(s->matrix.dy() + aliasedCoordinateDelta);
       
  3538         for (int i=0; i<lineCount; ++i) {
       
  3539             int dashOffset = int(s->lastPen.dashOffset());
       
  3540             if (s->flags.int_xform) {
       
  3541                 const QLine &l = lines[i];
       
  3542                 int x1 = l.x1() * m11 + dx;
       
  3543                 int y1 = l.y1() * m22 + dy;
       
  3544                 int x2 = l.x2() * m11 + dx;
       
  3545                 int y2 = l.y2() * m22 + dy;
       
  3546 
       
  3547                 const QRect brect(QPoint(x1, y1), QPoint(x2, y2));
       
  3548                 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  3549                 if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  3550                     drawLine_midpoint_i(x1, y1, x2, y2,
       
  3551                                         penBlend, &s->penData, mode, bounds);
       
  3552                 else
       
  3553                     drawLine_midpoint_dashed_i(x1, y1, x2, y2,
       
  3554                                                &s->lastPen, penBlend,
       
  3555                                                &s->penData, mode, bounds,
       
  3556                                                &dashOffset);
       
  3557             } else {
       
  3558                 QLineF line = lines[i] * s->matrix;
       
  3559                 const QRectF brect(QPointF(line.x1(), line.y1()),
       
  3560                                    QPointF(line.x2(), line.y2()));
       
  3561                 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  3562                 if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  3563                     drawLine_midpoint_i(int(line.x1()), int(line.y1()),
       
  3564                                         int(line.x2()), int(line.y2()),
       
  3565                                         penBlend, &s->penData, mode, bounds);
       
  3566                 else
       
  3567                     drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
       
  3568                                                int(line.x2()), int(line.y2()),
       
  3569                                                &s->lastPen, penBlend,
       
  3570                                                &s->penData, mode, bounds,
       
  3571                                                &dashOffset);
       
  3572             }
       
  3573         }
       
  3574     } else if (s->penData.blend) {
       
  3575         QPaintEngineEx::drawLines(lines, lineCount);
       
  3576     }
       
  3577 }
       
  3578 
       
  3579 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
       
  3580                                                      qreal width,
       
  3581                                                      int *dashIndex,
       
  3582                                                      qreal *dashOffset,
       
  3583                                                      bool *inDash)
       
  3584 {
       
  3585     Q_Q(QRasterPaintEngine);
       
  3586     QRasterPaintEngineState *s = q->state();
       
  3587 
       
  3588     const QPen &pen = s->lastPen;
       
  3589     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
       
  3590     const QVector<qreal> pattern = pen.dashPattern();
       
  3591 
       
  3592     qreal length = line.length();
       
  3593     Q_ASSERT(length > 0);
       
  3594     while (length > 0) {
       
  3595         const bool rasterize = *inDash;
       
  3596         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
       
  3597         QLineF l = line;
       
  3598 
       
  3599         if (dash >= length) {
       
  3600             dash = length;
       
  3601             *dashOffset += dash / width;
       
  3602             length = 0;
       
  3603         } else {
       
  3604             *dashOffset = 0;
       
  3605             *inDash = !(*inDash);
       
  3606             *dashIndex = (*dashIndex + 1) % pattern.size();
       
  3607             length -= dash;
       
  3608             l.setLength(dash);
       
  3609             line.setP1(l.p2());
       
  3610         }
       
  3611 
       
  3612         if (rasterize && dash != 0)
       
  3613             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
       
  3614     }
       
  3615 }
       
  3616 
       
  3617 /*!
       
  3618     \reimp
       
  3619 */
       
  3620 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
       
  3621 {
       
  3622 #ifdef QT_DEBUG_DRAW
       
  3623     qDebug() << " - QRasterPaintEngine::drawLine()";
       
  3624 #endif
       
  3625     Q_D(QRasterPaintEngine);
       
  3626     QRasterPaintEngineState *s = state();
       
  3627 
       
  3628     ensurePen();
       
  3629     if (!s->penData.blend)
       
  3630         return;
       
  3631     if (s->flags.fast_pen) {
       
  3632         QIntRect bounds;
       
  3633         bounds.set(d->deviceRect);
       
  3634         LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
       
  3635                             ? LineDrawNormal
       
  3636                             : LineDrawIncludeLastPixel;
       
  3637 
       
  3638         for (int i=0; i<lineCount; ++i) {
       
  3639             int dashOffset = int(s->lastPen.dashOffset());
       
  3640             QLineF line = (lines[i] * s->matrix).translated(aliasedCoordinateDelta, aliasedCoordinateDelta);
       
  3641             const QRectF brect(QPointF(line.x1(), line.y1()),
       
  3642                                QPointF(line.x2(), line.y2()));
       
  3643             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
       
  3644             if (qpen_style(s->lastPen) == Qt::SolidLine)
       
  3645                 drawLine_midpoint_i(int(line.x1()), int(line.y1()),
       
  3646                                     int(line.x2()), int(line.y2()),
       
  3647                                     penBlend, &s->penData, mode, bounds);
       
  3648             else
       
  3649                 drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
       
  3650                                            int(line.x2()), int(line.y2()),
       
  3651                                            &s->lastPen,
       
  3652                                            penBlend, &s->penData, mode,
       
  3653                                            bounds, &dashOffset);
       
  3654         }
       
  3655     } else {
       
  3656         QPaintEngineEx::drawLines(lines, lineCount);
       
  3657     }
       
  3658 }
       
  3659 
       
  3660 
       
  3661 /*!
       
  3662     \reimp
       
  3663 */
       
  3664 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
       
  3665 {
       
  3666     Q_D(QRasterPaintEngine);
       
  3667     QRasterPaintEngineState *s = state();
       
  3668 
       
  3669     ensurePen();
       
  3670     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
       
  3671          || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased))
       
  3672         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
       
  3673 #ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
       
  3674         && qMax(rect.width(), rect.height()) < 128 // integer math breakdown
       
  3675 #endif
       
  3676         && s->matrix.type() <= QTransform::TxScale) // no shear
       
  3677     {
       
  3678         ensureBrush();
       
  3679         const QRectF r = s->matrix.mapRect(rect);
       
  3680         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
       
  3681         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
       
  3682         const QRect brect = QRect(int(r.x()), int(r.y()),
       
  3683                                   int_dim(r.x(), r.width()),
       
  3684                                   int_dim(r.y(), r.height()));
       
  3685         if (brect == r) {
       
  3686             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
       
  3687                                    &s->penData, &s->brushData);
       
  3688             return;
       
  3689         }
       
  3690     }
       
  3691     QPaintEngineEx::drawEllipse(rect);
       
  3692 }
       
  3693 
       
  3694 /*!
       
  3695     \internal
       
  3696 */
       
  3697 #ifdef Q_WS_MAC
       
  3698 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
       
  3699 {
       
  3700     Q_D(QRasterPaintEngine);
       
  3701     d->cgContext = ctx;
       
  3702 }
       
  3703 
       
  3704 /*!
       
  3705     \internal
       
  3706 */
       
  3707 CGContextRef QRasterPaintEngine::getCGContext() const
       
  3708 {
       
  3709     Q_D(const QRasterPaintEngine);
       
  3710     return d->cgContext;
       
  3711 }
       
  3712 #endif
       
  3713 
       
  3714 #ifdef Q_WS_WIN
       
  3715 /*!
       
  3716     \internal
       
  3717 */
       
  3718 void QRasterPaintEngine::setDC(HDC hdc) {
       
  3719     Q_D(QRasterPaintEngine);
       
  3720     d->hdc = hdc;
       
  3721 }
       
  3722 
       
  3723 /*!
       
  3724     \internal
       
  3725 */
       
  3726 HDC QRasterPaintEngine::getDC() const
       
  3727 {
       
  3728     Q_D(const QRasterPaintEngine);
       
  3729     return d->hdc;
       
  3730 }
       
  3731 
       
  3732 /*!
       
  3733     \internal
       
  3734 */
       
  3735 void QRasterPaintEngine::releaseDC(HDC) const
       
  3736 {
       
  3737 }
       
  3738 
       
  3739 #endif
       
  3740 
       
  3741 /*!
       
  3742     \internal
       
  3743 */
       
  3744 QPoint QRasterPaintEngine::coordinateOffset() const
       
  3745 {
       
  3746     return QPoint(0, 0);
       
  3747 }
       
  3748 
       
  3749 /*!
       
  3750     Draws the given color \a spans with the specified \a color. The \a
       
  3751     count parameter specifies the number of spans.
       
  3752 
       
  3753     The default implementation does nothing; reimplement this function
       
  3754     to draw the given color \a spans with the specified \a color. Note
       
  3755     that this function \e must be reimplemented if the framebuffer is
       
  3756     not memory-mapped.
       
  3757 
       
  3758     \sa drawBufferSpan()
       
  3759 */
       
  3760 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
       
  3761 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
       
  3762 {
       
  3763     Q_UNUSED(spans);
       
  3764     Q_UNUSED(count);
       
  3765     Q_UNUSED(color);
       
  3766     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
       
  3767            "a non memory-mapped device");
       
  3768 }
       
  3769 
       
  3770 /*!
       
  3771     \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
       
  3772 
       
  3773     Draws the given \a buffer.
       
  3774 
       
  3775     The default implementation does nothing; reimplement this function
       
  3776     to draw a buffer that contains more than one color. Note that this
       
  3777     function \e must be reimplemented if the framebuffer is not
       
  3778     memory-mapped.
       
  3779 
       
  3780     The \a size parameter specifies the total size of the given \a
       
  3781     buffer, while the \a length parameter specifies the number of
       
  3782     pixels to draw. The buffer's position is given by (\a x, \a
       
  3783     y). The provided \a alpha value is added to each pixel in the
       
  3784     buffer when drawing.
       
  3785 
       
  3786     \sa drawColorSpans()
       
  3787 */
       
  3788 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
       
  3789                                         int x, int y, int length, uint const_alpha)
       
  3790 {
       
  3791     Q_UNUSED(buffer);
       
  3792     Q_UNUSED(bufsize);
       
  3793     Q_UNUSED(x);
       
  3794     Q_UNUSED(y);
       
  3795     Q_UNUSED(length);
       
  3796     Q_UNUSED(const_alpha);
       
  3797     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
       
  3798            "a non memory-mapped device");
       
  3799 }
       
  3800 #endif // Q_WS_QWS
       
  3801 
       
  3802 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
       
  3803 {
       
  3804     Q_ASSERT(fg);
       
  3805     if (!fg->blend)
       
  3806         return;
       
  3807     Q_D(QRasterPaintEngine);
       
  3808 
       
  3809     Q_ASSERT(image.depth() == 1);
       
  3810 
       
  3811     const int spanCount = 256;
       
  3812     QT_FT_Span spans[spanCount];
       
  3813     int n = 0;
       
  3814 
       
  3815     // Boundaries
       
  3816     int w = image.width();
       
  3817     int h = image.height();
       
  3818     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
       
  3819     int ymin = qMax(qRound(pos.y()), 0);
       
  3820     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
       
  3821     int xmin = qMax(qRound(pos.x()), 0);
       
  3822 
       
  3823     int x_offset = xmin - qRound(pos.x());
       
  3824 
       
  3825     QImage::Format format = image.format();
       
  3826     for (int y = ymin; y < ymax; ++y) {
       
  3827         const uchar *src = image.scanLine(y - qRound(pos.y()));
       
  3828         if (format == QImage::Format_MonoLSB) {
       
  3829             for (int x = 0; x < xmax - xmin; ++x) {
       
  3830                 int src_x = x + x_offset;
       
  3831                 uchar pixel = src[src_x >> 3];
       
  3832                 if (!pixel) {
       
  3833                     x += 7 - (src_x%8);
       
  3834                     continue;
       
  3835                 }
       
  3836                 if (pixel & (0x1 << (src_x & 7))) {
       
  3837                     spans[n].x = xmin + x;
       
  3838                     spans[n].y = y;
       
  3839                     spans[n].coverage = 255;
       
  3840                     int len = 1;
       
  3841                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
       
  3842                         ++src_x;
       
  3843                         ++len;
       
  3844                     }
       
  3845                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
       
  3846                     x += len;
       
  3847                     ++n;
       
  3848                     if (n == spanCount) {
       
  3849                         fg->blend(n, spans, fg);
       
  3850                         n = 0;
       
  3851                     }
       
  3852                 }
       
  3853             }
       
  3854         } else {
       
  3855             for (int x = 0; x < xmax - xmin; ++x) {
       
  3856                 int src_x = x + x_offset;
       
  3857                 uchar pixel = src[src_x >> 3];
       
  3858                 if (!pixel) {
       
  3859                     x += 7 - (src_x%8);
       
  3860                     continue;
       
  3861                 }
       
  3862                 if (pixel & (0x80 >> (x & 7))) {
       
  3863                     spans[n].x = xmin + x;
       
  3864                     spans[n].y = y;
       
  3865                     spans[n].coverage = 255;
       
  3866                     int len = 1;
       
  3867                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
       
  3868                         ++src_x;
       
  3869                         ++len;
       
  3870                     }
       
  3871                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
       
  3872                     x += len;
       
  3873                     ++n;
       
  3874                     if (n == spanCount) {
       
  3875                         fg->blend(n, spans, fg);
       
  3876                         n = 0;
       
  3877                     }
       
  3878                 }
       
  3879             }
       
  3880         }
       
  3881     }
       
  3882     if (n) {
       
  3883         fg->blend(n, spans, fg);
       
  3884         n = 0;
       
  3885     }
       
  3886 }
       
  3887 
       
  3888 /*!
       
  3889     \enum QRasterPaintEngine::ClipType
       
  3890     \internal
       
  3891 
       
  3892     \value RectClip Indicates that the currently set clip is a single rectangle.
       
  3893     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
       
  3894 */
       
  3895 
       
  3896 /*!
       
  3897     \internal
       
  3898     Returns the type of the clip currently set.
       
  3899 */
       
  3900 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
       
  3901 {
       
  3902     Q_D(const QRasterPaintEngine);
       
  3903 
       
  3904     const QClipData *clip = d->clip();
       
  3905     if (!clip || clip->hasRectClip)
       
  3906         return RectClip;
       
  3907     else
       
  3908         return ComplexClip;
       
  3909 }
       
  3910 
       
  3911 /*!
       
  3912     \internal
       
  3913     Returns the bounding rect of the currently set clip.
       
  3914 */
       
  3915 QRect QRasterPaintEngine::clipBoundingRect() const
       
  3916 {
       
  3917     Q_D(const QRasterPaintEngine);
       
  3918 
       
  3919     const QClipData *clip = d->clip();
       
  3920 
       
  3921     if (!clip)
       
  3922         return d->deviceRect;
       
  3923 
       
  3924     if (clip->hasRectClip)
       
  3925         return clip->clipRect;
       
  3926 
       
  3927     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
       
  3928 }
       
  3929 
       
  3930 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
       
  3931 {
       
  3932     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
       
  3933 
       
  3934     QVarLengthArray<short, 4096> buffer;
       
  3935 
       
  3936     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
       
  3937     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
       
  3938     result->initialize();
       
  3939 
       
  3940     for (int y = 0; y < c1->clipSpanHeight; ++y) {
       
  3941         const QSpan *c1_spans = c1ClipLines[y].spans;
       
  3942         int c1_count = c1ClipLines[y].count;
       
  3943         const QSpan *c2_spans = c2ClipLines[y].spans;
       
  3944         int c2_count = c2ClipLines[y].count;
       
  3945 
       
  3946         if (c1_count == 0 && c2_count == 0)
       
  3947             continue;
       
  3948         if (c1_count == 0) {
       
  3949             result->appendSpans(c2_spans, c2_count);
       
  3950             continue;
       
  3951         } else if (c2_count == 0) {
       
  3952             result->appendSpans(c1_spans, c1_count);
       
  3953             continue;
       
  3954         }
       
  3955 
       
  3956         // we need to merge the two
       
  3957 
       
  3958         // find required length
       
  3959         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
       
  3960                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
       
  3961         buffer.resize(max);
       
  3962         memset(buffer.data(), 0, buffer.size() * sizeof(short));
       
  3963 
       
  3964         // Fill with old spans.
       
  3965         for (int i = 0; i < c1_count; ++i) {
       
  3966             const QSpan *cs = c1_spans + i;
       
  3967             for (int j=cs->x; j<cs->x + cs->len; ++j)
       
  3968                 buffer[j] = cs->coverage;
       
  3969         }
       
  3970 
       
  3971         // Fill with new spans
       
  3972         for (int i = 0; i < c2_count; ++i) {
       
  3973             const QSpan *cs = c2_spans + i;
       
  3974             for (int j = cs->x; j < cs->x + cs->len; ++j) {
       
  3975                 buffer[j] += cs->coverage;
       
  3976                 if (buffer[j] > 255)
       
  3977                     buffer[j] = 255;
       
  3978             }
       
  3979         }
       
  3980 
       
  3981         int x = 0;
       
  3982         while (x<max) {
       
  3983 
       
  3984             // Skip to next span
       
  3985             while (x < max && buffer[x] == 0) ++x;
       
  3986             if (x >= max) break;
       
  3987 
       
  3988             int sx = x;
       
  3989             int coverage = buffer[x];
       
  3990 
       
  3991             // Find length of span
       
  3992             while (x < max && buffer[x] == coverage)
       
  3993                 ++x;
       
  3994 
       
  3995             result->appendSpan(sx, x - sx, y, coverage);
       
  3996         }
       
  3997     }
       
  3998 }
       
  3999 
       
  4000 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
       
  4001 {
       
  4002     Q_Q(QRasterPaintEngine);
       
  4003     QRasterPaintEngineState *s = q->state();
       
  4004 
       
  4005     rasterizer->setAntialiased(s->flags.antialiased);
       
  4006 
       
  4007     QRect clipRect(deviceRect);
       
  4008     ProcessSpans blend;
       
  4009     // ### get from optimized rectbased QClipData
       
  4010 
       
  4011     const QClipData *c = clip();
       
  4012     if (c) {
       
  4013         const QRect r(QPoint(c->xmin, c->ymin),
       
  4014                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
       
  4015         clipRect = clipRect.intersected(r);
       
  4016         blend = data->blend;
       
  4017     } else {
       
  4018         blend = data->unclipped_blend;
       
  4019     }
       
  4020 
       
  4021     rasterizer->setClipRect(clipRect);
       
  4022     rasterizer->initialize(blend, data);
       
  4023 }
       
  4024 
       
  4025 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
       
  4026                                           ProcessSpans callback,
       
  4027                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
       
  4028 {
       
  4029     if (!callback || !outline)
       
  4030         return;
       
  4031 
       
  4032     Q_Q(QRasterPaintEngine);
       
  4033     QRasterPaintEngineState *s = q->state();
       
  4034 
       
  4035     if (!s->flags.antialiased) {
       
  4036         initializeRasterizer(spanData);
       
  4037 
       
  4038         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
       
  4039                                       ? Qt::WindingFill
       
  4040                                       : Qt::OddEvenFill;
       
  4041 
       
  4042         rasterizer->rasterize(outline, fillRule);
       
  4043         return;
       
  4044     }
       
  4045 
       
  4046     rasterize(outline, callback, (void *)spanData, rasterBuffer);
       
  4047 }
       
  4048 
       
  4049 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
       
  4050                                           ProcessSpans callback,
       
  4051                                           void *userData, QRasterBuffer *)
       
  4052 {
       
  4053     if (!callback || !outline)
       
  4054         return;
       
  4055 
       
  4056     Q_Q(QRasterPaintEngine);
       
  4057     QRasterPaintEngineState *s = q->state();
       
  4058 
       
  4059     if (!s->flags.antialiased) {
       
  4060         rasterizer->setAntialiased(s->flags.antialiased);
       
  4061         rasterizer->setClipRect(deviceRect);
       
  4062         rasterizer->initialize(callback, userData);
       
  4063 
       
  4064         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
       
  4065                                       ? Qt::WindingFill
       
  4066                                       : Qt::OddEvenFill;
       
  4067 
       
  4068         rasterizer->rasterize(outline, fillRule);
       
  4069         return;
       
  4070     }
       
  4071 
       
  4072     void *data = userData;
       
  4073 
       
  4074     QT_FT_BBox clip_box = { deviceRect.x(),
       
  4075                             deviceRect.y(),
       
  4076                             deviceRect.x() + deviceRect.width(),
       
  4077                             deviceRect.y() + deviceRect.height() };
       
  4078 
       
  4079     QT_FT_Raster_Params rasterParams;
       
  4080     rasterParams.target = 0;
       
  4081     rasterParams.source = outline;
       
  4082     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
       
  4083     rasterParams.gray_spans = 0;
       
  4084     rasterParams.black_spans = 0;
       
  4085     rasterParams.bit_test = 0;
       
  4086     rasterParams.bit_set = 0;
       
  4087     rasterParams.user = data;
       
  4088     rasterParams.clip_box = clip_box;
       
  4089 
       
  4090     bool done = false;
       
  4091     int error;
       
  4092 
       
  4093     while (!done) {
       
  4094 
       
  4095         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
       
  4096         rasterParams.gray_spans = callback;
       
  4097         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
       
  4098 
       
  4099         // Out of memory, reallocate some more and try again...
       
  4100         if (error == -6) { // -6 is Result_err_OutOfMemory
       
  4101             int new_size = rasterPoolSize * 2;
       
  4102             if (new_size > 1024 * 1024) {
       
  4103                 qWarning("QPainter: Rasterization of primitive failed");
       
  4104                 return;
       
  4105             }
       
  4106 
       
  4107 #if defined(Q_WS_WIN64)
       
  4108             _aligned_free(rasterPoolBase);
       
  4109 #else
       
  4110             free(rasterPoolBase);
       
  4111 #endif
       
  4112 
       
  4113             rasterPoolSize = new_size;
       
  4114             rasterPoolBase =
       
  4115 #if defined(Q_WS_WIN64)
       
  4116                 // We make use of setjmp and longjmp in qgrayraster.c which requires
       
  4117                 // 16-byte alignment, hence we hardcode this requirement here..
       
  4118                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
       
  4119 #else
       
  4120                 (unsigned char *) malloc(rasterPoolSize);
       
  4121 #endif
       
  4122             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
       
  4123 
       
  4124             qt_ft_grays_raster.raster_done(*grayRaster.data());
       
  4125             qt_ft_grays_raster.raster_new(0, grayRaster.data());
       
  4126             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
       
  4127         } else {
       
  4128             done = true;
       
  4129         }
       
  4130     }
       
  4131 }
       
  4132 
       
  4133 void QRasterPaintEnginePrivate::recalculateFastImages()
       
  4134 {
       
  4135     Q_Q(QRasterPaintEngine);
       
  4136     QRasterPaintEngineState *s = q->state();
       
  4137 
       
  4138     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
       
  4139                            && rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
       
  4140                            && s->matrix.type() <= QTransform::TxShear;
       
  4141 }
       
  4142 
       
  4143 
       
  4144 
       
  4145 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
       
  4146 {
       
  4147     Q_ASSERT(image.depth() == 1);
       
  4148 
       
  4149     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
       
  4150     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
       
  4151 
       
  4152     QRgb fg = PREMUL(color.rgba());
       
  4153     QRgb bg = 0;
       
  4154 
       
  4155     int height = sourceImage.height();
       
  4156     int width = sourceImage.width();
       
  4157     for (int y=0; y<height; ++y) {
       
  4158         uchar *source = sourceImage.scanLine(y);
       
  4159         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
       
  4160         if (!source || !target)
       
  4161             QT_THROW(std::bad_alloc()); // we must have run out of memory
       
  4162         for (int x=0; x < width; ++x)
       
  4163             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
       
  4164     }
       
  4165     return dest;
       
  4166 }
       
  4167 
       
  4168 QRasterBuffer::~QRasterBuffer()
       
  4169 {
       
  4170 }
       
  4171 
       
  4172 void QRasterBuffer::init()
       
  4173 {
       
  4174     compositionMode = QPainter::CompositionMode_SourceOver;
       
  4175     monoDestinationWithClut = false;
       
  4176     destColor0 = 0;
       
  4177     destColor1 = 0;
       
  4178 }
       
  4179 
       
  4180 QImage::Format QRasterBuffer::prepare(QImage *image)
       
  4181 {
       
  4182     m_buffer = (uchar *)image->bits();
       
  4183     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
       
  4184     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
       
  4185     bytes_per_pixel = image->depth()/8;
       
  4186     bytes_per_line = image->bytesPerLine();
       
  4187 
       
  4188     format = image->format();
       
  4189     drawHelper = qDrawHelper + format;
       
  4190     if (image->depth() == 1 && image->colorTable().size() == 2) {
       
  4191         monoDestinationWithClut = true;
       
  4192         destColor0 = PREMUL(image->colorTable()[0]);
       
  4193         destColor1 = PREMUL(image->colorTable()[1]);
       
  4194     }
       
  4195 
       
  4196     return format;
       
  4197 }
       
  4198 
       
  4199 void QRasterBuffer::resetBuffer(int val)
       
  4200 {
       
  4201     memset(m_buffer, val, m_height*bytes_per_line);
       
  4202 }
       
  4203 
       
  4204 
       
  4205 #if defined(Q_WS_QWS)
       
  4206 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
       
  4207 {
       
  4208     m_buffer = reinterpret_cast<uchar*>(device->memory());
       
  4209     m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
       
  4210     m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
       
  4211     bytes_per_pixel = device->depth() / 8;
       
  4212     bytes_per_line = device->bytesPerLine();
       
  4213     format = device->format();
       
  4214 #ifndef QT_NO_RASTERCALLBACKS
       
  4215     if (!m_buffer)
       
  4216         drawHelper = qDrawHelperCallback + format;
       
  4217     else
       
  4218 #endif
       
  4219         drawHelper = qDrawHelper + format;
       
  4220 }
       
  4221 
       
  4222 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
       
  4223 {
       
  4224     switch (m) {
       
  4225     case PdmWidth:
       
  4226         return widget->frameGeometry().width();
       
  4227     case PdmHeight:
       
  4228         return widget->frameGeometry().height();
       
  4229     default:
       
  4230         break;
       
  4231     }
       
  4232 
       
  4233     return qt_paint_device_metric(widget, m);
       
  4234 }
       
  4235 
       
  4236 int QCustomRasterPaintDevice::bytesPerLine() const
       
  4237 {
       
  4238     return (width() * depth() + 7) / 8;
       
  4239 }
       
  4240 
       
  4241 #elif defined(Q_OS_SYMBIAN)
       
  4242 
       
  4243 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
       
  4244 {
       
  4245 }
       
  4246 
       
  4247 #endif // Q_OS_SYMBIAN
       
  4248 
       
  4249 /*!
       
  4250     \class QCustomRasterPaintDevice
       
  4251     \preliminary
       
  4252     \ingroup qws
       
  4253     \since 4.2
       
  4254 
       
  4255     \brief The QCustomRasterPaintDevice class is provided to activate
       
  4256     hardware accelerated paint engines in Qt for Embedded Linux.
       
  4257 
       
  4258     Note that this class is only available in \l{Qt for Embedded Linux}.
       
  4259 
       
  4260     In \l{Qt for Embedded Linux}, painting is a pure software
       
  4261     implementation. But starting with Qt 4.2, it is
       
  4262     possible to add an accelerated graphics driver to take advantage
       
  4263     of available hardware resources.
       
  4264 
       
  4265     Hardware acceleration is accomplished by creating a custom screen
       
  4266     driver, accelerating the copying from memory to the screen, and
       
  4267     implementing a custom paint engine accelerating the various
       
  4268     painting operations. Then a custom paint device (derived from the
       
  4269     QCustomRasterPaintDevice class) and a custom window surface
       
  4270     (derived from QWSWindowSurface) must be implemented to make
       
  4271     \l{Qt for Embedded Linux} aware of the accelerated driver.
       
  4272 
       
  4273     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
       
  4274     documentation for details.
       
  4275 
       
  4276     \sa QRasterPaintEngine, QPaintDevice
       
  4277 */
       
  4278 
       
  4279 /*!
       
  4280     \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
       
  4281 
       
  4282     Constructs a custom raster based paint device for the given
       
  4283     top-level \a widget.
       
  4284 */
       
  4285 
       
  4286 /*!
       
  4287     \fn int QCustomRasterPaintDevice::bytesPerLine() const
       
  4288 
       
  4289     Returns the number of bytes per line in the framebuffer. Note that
       
  4290     this number might be larger than the framebuffer width.
       
  4291 */
       
  4292 
       
  4293 /*!
       
  4294     \fn int QCustomRasterPaintDevice::devType() const
       
  4295     \internal
       
  4296 */
       
  4297 
       
  4298 /*!
       
  4299     \fn QImage::Format QCustomRasterPaintDevice::format() const
       
  4300 
       
  4301     Returns the format of the device's memory buffet.
       
  4302 
       
  4303     The default format is QImage::Format_ARGB32_Premultiplied. The
       
  4304     only other valid format is QImage::Format_RGB16.
       
  4305 */
       
  4306 
       
  4307 /*!
       
  4308     \fn void * QCustomRasterPaintDevice::memory () const
       
  4309 
       
  4310     Returns a pointer to the paint device's memory buffer, or 0 if no
       
  4311     such buffer exists.
       
  4312 */
       
  4313 
       
  4314 /*!
       
  4315     \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
       
  4316     \reimp
       
  4317 */
       
  4318 
       
  4319 /*!
       
  4320     \fn QSize QCustomRasterPaintDevice::size () const
       
  4321     \internal
       
  4322 */
       
  4323 
       
  4324 
       
  4325 QClipData::QClipData(int height)
       
  4326 {
       
  4327     clipSpanHeight = height;
       
  4328     m_clipLines = 0;
       
  4329 
       
  4330     allocated = 0;
       
  4331     m_spans = 0;
       
  4332     xmin = xmax = ymin = ymax = 0;
       
  4333     count = 0;
       
  4334 
       
  4335     enabled = true;
       
  4336     hasRectClip = hasRegionClip = false;
       
  4337 }
       
  4338 
       
  4339 QClipData::~QClipData()
       
  4340 {
       
  4341     if (m_clipLines)
       
  4342         free(m_clipLines);
       
  4343     if (m_spans)
       
  4344         free(m_spans);
       
  4345 }
       
  4346 
       
  4347 void QClipData::initialize()
       
  4348 {
       
  4349     if (m_spans)
       
  4350         return;
       
  4351 
       
  4352     if (!m_clipLines)
       
  4353         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
       
  4354 
       
  4355     Q_CHECK_PTR(m_clipLines);
       
  4356     QT_TRY {
       
  4357         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
       
  4358         allocated = clipSpanHeight;
       
  4359         Q_CHECK_PTR(m_spans);
       
  4360 
       
  4361         QT_TRY {
       
  4362             if (hasRectClip) {
       
  4363                 int y = 0;
       
  4364                 while (y < ymin) {
       
  4365                     m_clipLines[y].spans = 0;
       
  4366                     m_clipLines[y].count = 0;
       
  4367                     ++y;
       
  4368                 }
       
  4369 
       
  4370                 const int len = clipRect.width();
       
  4371                 count = 0;
       
  4372                 while (y < ymax) {
       
  4373                     QSpan *span = m_spans + count;
       
  4374                     span->x = xmin;
       
  4375                     span->len = len;
       
  4376                     span->y = y;
       
  4377                     span->coverage = 255;
       
  4378                     ++count;
       
  4379 
       
  4380                     m_clipLines[y].spans = span;
       
  4381                     m_clipLines[y].count = 1;
       
  4382                     ++y;
       
  4383                 }
       
  4384 
       
  4385                 while (y < clipSpanHeight) {
       
  4386                     m_clipLines[y].spans = 0;
       
  4387                     m_clipLines[y].count = 0;
       
  4388                     ++y;
       
  4389                 }
       
  4390             } else if (hasRegionClip) {
       
  4391 
       
  4392                 const QVector<QRect> rects = clipRegion.rects();
       
  4393                 const int numRects = rects.size();
       
  4394 
       
  4395                 { // resize
       
  4396                     const int maxSpans = (ymax - ymin) * numRects;
       
  4397                     if (maxSpans > allocated) {
       
  4398                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
       
  4399                         allocated = maxSpans;
       
  4400                     }
       
  4401                 }
       
  4402 
       
  4403                 int y = 0;
       
  4404                 int firstInBand = 0;
       
  4405                 count = 0;
       
  4406                 while (firstInBand < numRects) {
       
  4407                     const int currMinY = rects.at(firstInBand).y();
       
  4408                     const int currMaxY = currMinY + rects.at(firstInBand).height();
       
  4409 
       
  4410                     while (y < currMinY) {
       
  4411                         m_clipLines[y].spans = 0;
       
  4412                         m_clipLines[y].count = 0;
       
  4413                         ++y;
       
  4414                     }
       
  4415 
       
  4416                     int lastInBand = firstInBand;
       
  4417                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
       
  4418                         ++lastInBand;
       
  4419 
       
  4420                     while (y < currMaxY) {
       
  4421 
       
  4422                         m_clipLines[y].spans = m_spans + count;
       
  4423                         m_clipLines[y].count = lastInBand - firstInBand + 1;
       
  4424 
       
  4425                         for (int r = firstInBand; r <= lastInBand; ++r) {
       
  4426                             const QRect &currRect = rects.at(r);
       
  4427                             QSpan *span = m_spans + count;
       
  4428                             span->x = currRect.x();
       
  4429                             span->len = currRect.width();
       
  4430                             span->y = y;
       
  4431                             span->coverage = 255;
       
  4432                             ++count;
       
  4433                         }
       
  4434                         ++y;
       
  4435                     }
       
  4436 
       
  4437                     firstInBand = lastInBand + 1;
       
  4438                 }
       
  4439 
       
  4440                 Q_ASSERT(count <= allocated);
       
  4441 
       
  4442                 while (y < clipSpanHeight) {
       
  4443                     m_clipLines[y].spans = 0;
       
  4444                     m_clipLines[y].count = 0;
       
  4445                     ++y;
       
  4446                 }
       
  4447 
       
  4448             }
       
  4449         } QT_CATCH(...) {
       
  4450             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
       
  4451             m_spans = 0;
       
  4452             QT_RETHROW;
       
  4453         }
       
  4454     } QT_CATCH(...) {
       
  4455         free(m_clipLines); // same for clipLines
       
  4456         m_clipLines = 0;
       
  4457         QT_RETHROW;
       
  4458     }
       
  4459 }
       
  4460 
       
  4461 void QClipData::fixup()
       
  4462 {
       
  4463     Q_ASSERT(m_spans);
       
  4464 
       
  4465     if (count == 0) {
       
  4466         ymin = ymax = xmin = xmax = 0;
       
  4467         return;
       
  4468     }
       
  4469 
       
  4470 //      qDebug("QClipData::fixup: count=%d",count);
       
  4471     int y = -1;
       
  4472     ymin = m_spans[0].y;
       
  4473     ymax = m_spans[count-1].y + 1;
       
  4474     xmin = INT_MAX;
       
  4475     xmax = 0;
       
  4476 
       
  4477     bool isRect = true;
       
  4478     int left = m_spans[0].x;
       
  4479     int right = m_spans[0].x + m_spans[0].len;
       
  4480 
       
  4481     for (int i = 0; i < count; ++i) {
       
  4482         if (m_spans[i].y != y) {
       
  4483             if (m_spans[i].y != y + 1 && y != -1) {
       
  4484                 isRect = false;
       
  4485             }
       
  4486             y = m_spans[i].y;
       
  4487             m_clipLines[y].spans = m_spans+i;
       
  4488             m_clipLines[y].count = 0;
       
  4489 //              qDebug() << "        new line: y=" << y;
       
  4490         }
       
  4491         ++m_clipLines[y].count;
       
  4492         int sl = (int) m_spans[i].x;
       
  4493         int sr = sl + m_spans[i].len;
       
  4494 
       
  4495         xmin = qMin(xmin, (int)m_spans[i].x);
       
  4496         xmax = qMax(xmax, (int)m_spans[i].x + m_spans[i].len);
       
  4497 
       
  4498         if (sl != left || sr != right)
       
  4499             isRect = false;
       
  4500     }
       
  4501 //     qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d %s", xmin, xmax, ymin, ymax, isRect ? "rectangular" : "");
       
  4502 
       
  4503     if (isRect) {
       
  4504         hasRectClip = true;
       
  4505         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
       
  4506     }
       
  4507 }
       
  4508 
       
  4509 /*
       
  4510     Convert \a rect to clip spans.
       
  4511  */
       
  4512 void QClipData::setClipRect(const QRect &rect)
       
  4513 {
       
  4514     if (hasRectClip && rect == clipRect)
       
  4515         return;
       
  4516 
       
  4517 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
       
  4518     hasRectClip = true;
       
  4519     hasRegionClip = false;
       
  4520     clipRect = rect;
       
  4521 
       
  4522     xmin = rect.x();
       
  4523     xmax = rect.x() + rect.width();
       
  4524     ymin = qMin(rect.y(), clipSpanHeight);
       
  4525     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
       
  4526 
       
  4527     if (m_spans) {
       
  4528         free(m_spans);
       
  4529         m_spans = 0;
       
  4530     }
       
  4531 
       
  4532 //    qDebug() << xmin << xmax << ymin << ymax;
       
  4533 }
       
  4534 
       
  4535 /*
       
  4536     Convert \a region to clip spans.
       
  4537  */
       
  4538 void QClipData::setClipRegion(const QRegion &region)
       
  4539 {
       
  4540     if (region.numRects() == 1) {
       
  4541         setClipRect(region.rects().at(0));
       
  4542         return;
       
  4543     }
       
  4544 
       
  4545     hasRegionClip = true;
       
  4546     hasRectClip = false;
       
  4547     clipRegion = region;
       
  4548 
       
  4549     { // set bounding rect
       
  4550         const QRect rect = region.boundingRect();
       
  4551         xmin = rect.x();
       
  4552         xmax = rect.x() + rect.width();
       
  4553         ymin = rect.y();
       
  4554         ymax = rect.y() + rect.height();
       
  4555     }
       
  4556 
       
  4557     if (m_spans) {
       
  4558         free(m_spans);
       
  4559         m_spans = 0;
       
  4560     }
       
  4561 
       
  4562 }
       
  4563 
       
  4564 /*!
       
  4565     \internal
       
  4566     spans must be sorted on y
       
  4567 */
       
  4568 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
       
  4569                                        const QSpan *spans, const QSpan *end,
       
  4570                                        QSpan **outSpans, int available)
       
  4571 {
       
  4572     const_cast<QClipData *>(clip)->initialize();
       
  4573 
       
  4574     QSpan *out = *outSpans;
       
  4575 
       
  4576     const QSpan *clipSpans = clip->m_spans + *currentClip;
       
  4577     const QSpan *clipEnd = clip->m_spans + clip->count;
       
  4578 
       
  4579     while (available && spans < end ) {
       
  4580         if (clipSpans >= clipEnd) {
       
  4581             spans = end;
       
  4582             break;
       
  4583         }
       
  4584         if (clipSpans->y > spans->y) {
       
  4585             ++spans;
       
  4586             continue;
       
  4587         }
       
  4588         if (spans->y != clipSpans->y) {
       
  4589             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
       
  4590                 clipSpans = clip->m_clipLines[spans->y].spans;
       
  4591             else
       
  4592                 ++clipSpans;
       
  4593             continue;
       
  4594         }
       
  4595         Q_ASSERT(spans->y == clipSpans->y);
       
  4596 
       
  4597         int sx1 = spans->x;
       
  4598         int sx2 = sx1 + spans->len;
       
  4599         int cx1 = clipSpans->x;
       
  4600         int cx2 = cx1 + clipSpans->len;
       
  4601 
       
  4602         if (cx1 < sx1 && cx2 < sx1) {
       
  4603             ++clipSpans;
       
  4604             continue;
       
  4605         } else if (sx1 < cx1 && sx2 < cx1) {
       
  4606             ++spans;
       
  4607             continue;
       
  4608         }
       
  4609         int x = qMax(sx1, cx1);
       
  4610         int len = qMin(sx2, cx2) - x;
       
  4611         if (len) {
       
  4612             out->x = qMax(sx1, cx1);
       
  4613             out->len = qMin(sx2, cx2) - out->x;
       
  4614             out->y = spans->y;
       
  4615             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
       
  4616             ++out;
       
  4617             --available;
       
  4618         }
       
  4619         if (sx2 < cx2) {
       
  4620             ++spans;
       
  4621         } else {
       
  4622             ++clipSpans;
       
  4623         }
       
  4624     }
       
  4625 
       
  4626     *outSpans = out;
       
  4627     *currentClip = clipSpans - clip->m_spans;
       
  4628     return spans;
       
  4629 }
       
  4630 
       
  4631 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
       
  4632 {
       
  4633 //     qDebug() << "qt_span_fill_clipped" << spanCount;
       
  4634     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
       
  4635 
       
  4636     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
       
  4637 
       
  4638     const int NSPANS = 256;
       
  4639     QSpan cspans[NSPANS];
       
  4640     int currentClip = 0;
       
  4641     const QSpan *end = spans + spanCount;
       
  4642     while (spans < end) {
       
  4643         QSpan *clipped = cspans;
       
  4644         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
       
  4645 //         qDebug() << "processed " << processed << "clipped" << clipped-cspans
       
  4646 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
       
  4647 
       
  4648         if (clipped - cspans)
       
  4649             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
       
  4650     }
       
  4651 }
       
  4652 
       
  4653 /*
       
  4654     \internal
       
  4655     Clip spans to \a{clip}-rectangle.
       
  4656     Returns number of unclipped spans
       
  4657 */
       
  4658 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
       
  4659                               const QRect &clip)
       
  4660 {
       
  4661     const short minx = clip.left();
       
  4662     const short miny = clip.top();
       
  4663     const short maxx = clip.right();
       
  4664     const short maxy = clip.bottom();
       
  4665 
       
  4666     int n = 0;
       
  4667     for (int i = 0; i < numSpans; ++i) {
       
  4668         if (spans[i].y > maxy)
       
  4669             break;
       
  4670         if (spans[i].y < miny
       
  4671             || spans[i].x > maxx
       
  4672             || spans[i].x + spans[i].len <= minx) {
       
  4673             continue;
       
  4674         }
       
  4675         if (spans[i].x < minx) {
       
  4676             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
       
  4677             spans[n].x = minx;
       
  4678         } else {
       
  4679             spans[n].x = spans[i].x;
       
  4680             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
       
  4681         }
       
  4682         if (spans[n].len == 0)
       
  4683             continue;
       
  4684         spans[n].y = spans[i].y;
       
  4685         spans[n].coverage = spans[i].coverage;
       
  4686         ++n;
       
  4687     }
       
  4688     return n;
       
  4689 }
       
  4690 
       
  4691 
       
  4692 static void qt_span_fill_clipRect(int count, const QSpan *spans,
       
  4693                                   void *userData)
       
  4694 {
       
  4695     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
       
  4696     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
       
  4697 
       
  4698     Q_ASSERT(fillData->clip);
       
  4699     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
       
  4700 
       
  4701     // hw: check if this const_cast<> is safe!!!
       
  4702     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
       
  4703                                fillData->clip->clipRect);
       
  4704     if (count > 0)
       
  4705         fillData->unclipped_blend(count, spans, fillData);
       
  4706 }
       
  4707 
       
  4708 static void qt_span_clip(int count, const QSpan *spans, void *userData)
       
  4709 {
       
  4710     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
       
  4711 
       
  4712 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
       
  4713 //     for (int i = 0; i < qMin(count, 10); ++i) {
       
  4714 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
       
  4715 //     }
       
  4716 
       
  4717     switch (clipData->operation) {
       
  4718 
       
  4719     case Qt::IntersectClip:
       
  4720         {
       
  4721             QClipData *newClip = clipData->newClip;
       
  4722             newClip->initialize();
       
  4723 
       
  4724             int currentClip = 0;
       
  4725             const QSpan *end = spans + count;
       
  4726             while (spans < end) {
       
  4727                 QSpan *newspans = newClip->m_spans + newClip->count;
       
  4728                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
       
  4729                                            &newspans, newClip->allocated - newClip->count);
       
  4730                 newClip->count = newspans - newClip->m_spans;
       
  4731                 if (spans < end) {
       
  4732                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
       
  4733                     newClip->allocated *= 2;
       
  4734                 }
       
  4735             }
       
  4736         }
       
  4737         break;
       
  4738 
       
  4739     case Qt::UniteClip:
       
  4740     case Qt::ReplaceClip:
       
  4741         clipData->newClip->appendSpans(spans, count);
       
  4742         break;
       
  4743     case Qt::NoClip:
       
  4744         break;
       
  4745     }
       
  4746 }
       
  4747 
       
  4748 #ifndef QT_NO_DEBUG
       
  4749 QImage QRasterBuffer::bufferImage() const
       
  4750 {
       
  4751     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
       
  4752 
       
  4753     for (int y = 0; y < m_height; ++y) {
       
  4754         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
       
  4755 
       
  4756         for (int x=0; x<m_width; ++x) {
       
  4757             uint argb = span[x];
       
  4758             image.setPixel(x, y, argb);
       
  4759         }
       
  4760     }
       
  4761     return image;
       
  4762 }
       
  4763 #endif
       
  4764 
       
  4765 
       
  4766 void QRasterBuffer::flushToARGBImage(QImage *target) const
       
  4767 {
       
  4768     int w = qMin(m_width, target->width());
       
  4769     int h = qMin(m_height, target->height());
       
  4770 
       
  4771     for (int y=0; y<h; ++y) {
       
  4772         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
       
  4773         QRgb *dest = (QRgb *) target->scanLine(y);
       
  4774         for (int x=0; x<w; ++x) {
       
  4775             QRgb pixel = sourceLine[x];
       
  4776             int alpha = qAlpha(pixel);
       
  4777             if (!alpha) {
       
  4778                 dest[x] = 0;
       
  4779             } else {
       
  4780                 dest[x] = (alpha << 24)
       
  4781                         | ((255*qRed(pixel)/alpha) << 16)
       
  4782                         | ((255*qGreen(pixel)/alpha) << 8)
       
  4783                         | ((255*qBlue(pixel)/alpha) << 0);
       
  4784             }
       
  4785         }
       
  4786     }
       
  4787 }
       
  4788 
       
  4789 
       
  4790 class QGradientCache
       
  4791 {
       
  4792     struct CacheInfo
       
  4793     {
       
  4794         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
       
  4795             stops(s), opacity(op), interpolationMode(mode) {}
       
  4796         uint buffer[GRADIENT_STOPTABLE_SIZE];
       
  4797         QGradientStops stops;
       
  4798         int opacity;
       
  4799         QGradient::InterpolationMode interpolationMode;
       
  4800     };
       
  4801 
       
  4802     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
       
  4803 
       
  4804 public:
       
  4805     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
       
  4806         quint64 hash_val = 0;
       
  4807 
       
  4808         QGradientStops stops = gradient.stops();
       
  4809         for (int i = 0; i < stops.size() && i <= 2; i++)
       
  4810             hash_val += stops[i].second.rgba();
       
  4811 
       
  4812         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
       
  4813 
       
  4814         if (it == cache.constEnd())
       
  4815             return addCacheElement(hash_val, gradient, opacity);
       
  4816         else {
       
  4817             do {
       
  4818                 const CacheInfo &cache_info = it.value();
       
  4819                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
       
  4820                     return cache_info.buffer;
       
  4821                 ++it;
       
  4822             } while (it != cache.constEnd() && it.key() == hash_val);
       
  4823             // an exact match for these stops and opacity was not found, create new cache
       
  4824             return addCacheElement(hash_val, gradient, opacity);
       
  4825         }
       
  4826     }
       
  4827 
       
  4828     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
       
  4829 protected:
       
  4830     inline int maxCacheSize() const { return 60; }
       
  4831     inline void generateGradientColorTable(const QGradient& g,
       
  4832                                            uint *colorTable,
       
  4833                                            int size, int opacity) const;
       
  4834     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
       
  4835         if (cache.size() == maxCacheSize()) {
       
  4836             int elem_to_remove = qrand() % maxCacheSize();
       
  4837             cache.remove(cache.keys()[elem_to_remove]); // may remove more than 1, but OK
       
  4838         }
       
  4839         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
       
  4840         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
       
  4841         return cache.insert(hash_val, cache_entry).value().buffer;
       
  4842     }
       
  4843 
       
  4844     QGradientColorTableHash cache;
       
  4845 };
       
  4846 
       
  4847 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
       
  4848 {
       
  4849     QGradientStops stops = gradient.stops();
       
  4850     int stopCount = stops.count();
       
  4851     Q_ASSERT(stopCount > 0);
       
  4852 
       
  4853     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
       
  4854 
       
  4855     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
       
  4856     if (stopCount == 1) {
       
  4857         current_color = PREMUL(current_color);
       
  4858         for (int i = 0; i < size; ++i)
       
  4859             colorTable[i] = current_color;
       
  4860         return;
       
  4861     }
       
  4862 
       
  4863     // The position where the gradient begins and ends
       
  4864     qreal begin_pos = stops[0].first;
       
  4865     qreal end_pos = stops[stopCount-1].first;
       
  4866 
       
  4867     int pos = 0; // The position in the color table.
       
  4868     uint next_color;
       
  4869 
       
  4870     qreal incr = 1 / qreal(size); // the double increment.
       
  4871     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
       
  4872 
       
  4873      // Up to first point
       
  4874     colorTable[pos++] = PREMUL(current_color);
       
  4875     while (dpos <= begin_pos) {
       
  4876         colorTable[pos] = colorTable[pos - 1];
       
  4877         ++pos;
       
  4878         dpos += incr;
       
  4879     }
       
  4880 
       
  4881     int current_stop = 0; // We always interpolate between current and current + 1.
       
  4882 
       
  4883     qreal t; // position between current left and right stops
       
  4884     qreal t_delta; // the t increment per entry in the color table
       
  4885 
       
  4886     if (dpos < end_pos) {
       
  4887         // Gradient area
       
  4888         while (dpos > stops[current_stop+1].first)
       
  4889             ++current_stop;
       
  4890 
       
  4891         if (current_stop != 0)
       
  4892             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
       
  4893         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
       
  4894 
       
  4895         if (colorInterpolation) {
       
  4896             current_color = PREMUL(current_color);
       
  4897             next_color = PREMUL(next_color);
       
  4898         }
       
  4899 
       
  4900         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
       
  4901         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
       
  4902         t = (dpos - stops[current_stop].first) * c;
       
  4903         t_delta = incr * c;
       
  4904 
       
  4905         while (true) {
       
  4906             Q_ASSERT(current_stop < stopCount);
       
  4907 
       
  4908             int dist = qRound(t);
       
  4909             int idist = 256 - dist;
       
  4910 
       
  4911             if (colorInterpolation)
       
  4912                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
       
  4913             else
       
  4914                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
       
  4915 
       
  4916             ++pos;
       
  4917             dpos += incr;
       
  4918 
       
  4919             if (dpos >= end_pos)
       
  4920                 break;
       
  4921 
       
  4922             t += t_delta;
       
  4923 
       
  4924             int skip = 0;
       
  4925             while (dpos > stops[current_stop+skip+1].first)
       
  4926                 ++skip;
       
  4927 
       
  4928             if (skip != 0) {
       
  4929                 current_stop += skip;
       
  4930                 if (skip == 1)
       
  4931                     current_color = next_color;
       
  4932                 else
       
  4933                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
       
  4934                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
       
  4935 
       
  4936                 if (colorInterpolation) {
       
  4937                     if (skip != 1)
       
  4938                         current_color = PREMUL(current_color);
       
  4939                     next_color = PREMUL(next_color);
       
  4940                 }
       
  4941 
       
  4942                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
       
  4943                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
       
  4944                 t = (dpos - stops[current_stop].first) * c;
       
  4945                 t_delta = incr * c;
       
  4946             }
       
  4947         }
       
  4948     }
       
  4949 
       
  4950     // After last point
       
  4951     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
       
  4952     while (pos < size - 1) {
       
  4953         colorTable[pos] = current_color;
       
  4954         ++pos;
       
  4955     }
       
  4956 
       
  4957     // Make sure the last color stop is represented at the end of the table
       
  4958     colorTable[size - 1] = current_color;
       
  4959 }
       
  4960 
       
  4961 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
       
  4962 
       
  4963 
       
  4964 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
       
  4965 {
       
  4966     rasterBuffer = rb;
       
  4967 #ifdef Q_WS_QWS
       
  4968     rasterEngine = const_cast<QRasterPaintEngine *>(pe);
       
  4969 #endif
       
  4970     type = None;
       
  4971     txop = 0;
       
  4972     bilinear = false;
       
  4973     m11 = m22 = m33 = 1.;
       
  4974     m12 = m13 = m21 = m23 = dx = dy = 0.0;
       
  4975     clip = pe ? pe->d_func()->clip() : 0;
       
  4976 }
       
  4977 
       
  4978 extern QImage qt_imageForBrush(int brushStyle, bool invert);
       
  4979 
       
  4980 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
       
  4981 {
       
  4982     Qt::BrushStyle brushStyle = qbrush_style(brush);
       
  4983     switch (brushStyle) {
       
  4984     case Qt::SolidPattern: {
       
  4985         type = Solid;
       
  4986         QColor c = qbrush_color(brush);
       
  4987         solid.color = PREMUL(ARGB_COMBINE_ALPHA(c.rgba(), alpha));
       
  4988         if ((solid.color & 0xff000000) == 0
       
  4989             && compositionMode == QPainter::CompositionMode_SourceOver) {
       
  4990             type = None;
       
  4991         }
       
  4992         break;
       
  4993     }
       
  4994 
       
  4995     case Qt::LinearGradientPattern:
       
  4996         {
       
  4997             type = LinearGradient;
       
  4998             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
       
  4999             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
       
  5000             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
       
  5001             gradient.spread = g->spread();
       
  5002 
       
  5003             QLinearGradientData &linearData = gradient.linear;
       
  5004 
       
  5005             linearData.origin.x = g->start().x();
       
  5006             linearData.origin.y = g->start().y();
       
  5007             linearData.end.x = g->finalStop().x();
       
  5008             linearData.end.y = g->finalStop().y();
       
  5009             break;
       
  5010         }
       
  5011 
       
  5012     case Qt::RadialGradientPattern:
       
  5013         {
       
  5014             type = RadialGradient;
       
  5015             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
       
  5016             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
       
  5017             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
       
  5018             gradient.spread = g->spread();
       
  5019 
       
  5020             QRadialGradientData &radialData = gradient.radial;
       
  5021 
       
  5022             QPointF center = g->center();
       
  5023             radialData.center.x = center.x();
       
  5024             radialData.center.y = center.y();
       
  5025             QPointF focal = g->focalPoint();
       
  5026             radialData.focal.x = focal.x();
       
  5027             radialData.focal.y = focal.y();
       
  5028             radialData.radius = g->radius();
       
  5029         }
       
  5030         break;
       
  5031 
       
  5032     case Qt::ConicalGradientPattern:
       
  5033         {
       
  5034             type = ConicalGradient;
       
  5035             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
       
  5036             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
       
  5037             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
       
  5038             gradient.spread = QGradient::RepeatSpread;
       
  5039 
       
  5040             QConicalGradientData &conicalData = gradient.conical;
       
  5041 
       
  5042             QPointF center = g->center();
       
  5043             conicalData.center.x = center.x();
       
  5044             conicalData.center.y = center.y();
       
  5045             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
       
  5046         }
       
  5047         break;
       
  5048 
       
  5049     case Qt::Dense1Pattern:
       
  5050     case Qt::Dense2Pattern:
       
  5051     case Qt::Dense3Pattern:
       
  5052     case Qt::Dense4Pattern:
       
  5053     case Qt::Dense5Pattern:
       
  5054     case Qt::Dense6Pattern:
       
  5055     case Qt::Dense7Pattern:
       
  5056     case Qt::HorPattern:
       
  5057     case Qt::VerPattern:
       
  5058     case Qt::CrossPattern:
       
  5059     case Qt::BDiagPattern:
       
  5060     case Qt::FDiagPattern:
       
  5061     case Qt::DiagCrossPattern:
       
  5062         type = Texture;
       
  5063         if (!tempImage)
       
  5064             tempImage = new QImage();
       
  5065         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
       
  5066         initTexture(tempImage, alpha, QTextureData::Tiled);
       
  5067         break;
       
  5068     case Qt::TexturePattern:
       
  5069         type = Texture;
       
  5070         if (!tempImage)
       
  5071             tempImage = new QImage();
       
  5072 
       
  5073         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
       
  5074             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
       
  5075         else
       
  5076             *tempImage = brush.textureImage();
       
  5077         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
       
  5078         break;
       
  5079 
       
  5080     case Qt::NoBrush:
       
  5081     default:
       
  5082         type = None;
       
  5083         break;
       
  5084     }
       
  5085     adjustSpanMethods();
       
  5086 }
       
  5087 
       
  5088 void QSpanData::adjustSpanMethods()
       
  5089 {
       
  5090     bitmapBlit = 0;
       
  5091     alphamapBlit = 0;
       
  5092     alphaRGBBlit = 0;
       
  5093 
       
  5094     fillRect = 0;
       
  5095 
       
  5096     switch(type) {
       
  5097     case None:
       
  5098         unclipped_blend = 0;
       
  5099         break;
       
  5100     case Solid:
       
  5101         unclipped_blend = rasterBuffer->drawHelper->blendColor;
       
  5102         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
       
  5103         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
       
  5104         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
       
  5105         fillRect = rasterBuffer->drawHelper->fillRect;
       
  5106         break;
       
  5107     case LinearGradient:
       
  5108     case RadialGradient:
       
  5109     case ConicalGradient:
       
  5110         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
       
  5111         break;
       
  5112     case Texture:
       
  5113 #ifdef Q_WS_QWS
       
  5114 #ifndef QT_NO_RASTERCALLBACKS
       
  5115         if (!rasterBuffer->buffer())
       
  5116             unclipped_blend = qBlendTextureCallback;
       
  5117         else
       
  5118 #endif
       
  5119             unclipped_blend = qBlendTexture;
       
  5120 #else
       
  5121         unclipped_blend = qBlendTexture;
       
  5122 #endif
       
  5123         break;
       
  5124     }
       
  5125     // setup clipping
       
  5126     if (!unclipped_blend) {
       
  5127         blend = 0;
       
  5128     } else if (!clip) {
       
  5129         blend = unclipped_blend;
       
  5130     } else if (clip->hasRectClip) {
       
  5131         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
       
  5132     } else {
       
  5133         blend = qt_span_fill_clipped;
       
  5134     }
       
  5135 }
       
  5136 
       
  5137 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
       
  5138 {
       
  5139     QTransform delta;
       
  5140     // make sure we round off correctly in qdrawhelper.cpp
       
  5141     delta.translate(1.0 / 65536, 1.0 / 65536);
       
  5142 
       
  5143     QTransform inv = (delta * matrix).inverted();
       
  5144     m11 = inv.m11();
       
  5145     m12 = inv.m12();
       
  5146     m13 = inv.m13();
       
  5147     m21 = inv.m21();
       
  5148     m22 = inv.m22();
       
  5149     m23 = inv.m23();
       
  5150     m33 = inv.m33();
       
  5151     dx = inv.dx();
       
  5152     dy = inv.dy();
       
  5153     txop = inv.type();
       
  5154     bilinear = bilin;
       
  5155 
       
  5156     const bool affine = !m13 && !m23;
       
  5157     fast_matrix = affine
       
  5158         && m11 * m11 + m21 * m21 < 1e4
       
  5159         && m12 * m12 + m22 * m22 < 1e4
       
  5160         && qAbs(dx) < 1e4
       
  5161         && qAbs(dy) < 1e4;
       
  5162 
       
  5163     adjustSpanMethods();
       
  5164 }
       
  5165 
       
  5166 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
       
  5167 
       
  5168 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
       
  5169 {
       
  5170     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
       
  5171     if (!d || d->height == 0) {
       
  5172         texture.imageData = 0;
       
  5173         texture.width = 0;
       
  5174         texture.height = 0;
       
  5175         texture.x1 = 0;
       
  5176         texture.y1 = 0;
       
  5177         texture.x2 = 0;
       
  5178         texture.y2 = 0;
       
  5179         texture.bytesPerLine = 0;
       
  5180         texture.format = QImage::Format_Invalid;
       
  5181         texture.colorTable = 0;
       
  5182         texture.hasAlpha = alpha != 256;
       
  5183     } else {
       
  5184         texture.imageData = d->data;
       
  5185         texture.width = d->width;
       
  5186         texture.height = d->height;
       
  5187 
       
  5188         if (sourceRect.isNull()) {
       
  5189             texture.x1 = 0;
       
  5190             texture.y1 = 0;
       
  5191             texture.x2 = texture.width;
       
  5192             texture.y2 = texture.height;
       
  5193         } else {
       
  5194             texture.x1 = sourceRect.x();
       
  5195             texture.y1 = sourceRect.y();
       
  5196             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
       
  5197             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
       
  5198         }
       
  5199 
       
  5200         texture.bytesPerLine = d->bytes_per_line;
       
  5201 
       
  5202         texture.format = d->format;
       
  5203         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
       
  5204         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
       
  5205     }
       
  5206     texture.const_alpha = alpha;
       
  5207     texture.type = _type;
       
  5208 
       
  5209     adjustSpanMethods();
       
  5210 }
       
  5211 
       
  5212 #ifdef Q_WS_WIN
       
  5213 
       
  5214 
       
  5215 #endif
       
  5216 
       
  5217 
       
  5218 /*!
       
  5219     \internal
       
  5220 
       
  5221     Draws a line using the floating point midpoint algorithm. The line
       
  5222     \a line is already in device coords at this point.
       
  5223 */
       
  5224 
       
  5225 static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
       
  5226                                 LineDrawMode style, const QIntRect &devRect)
       
  5227 {
       
  5228 #ifdef QT_DEBUG_DRAW
       
  5229     qDebug() << "   - drawLine_midpoint_i" << QLine(QPoint(x1, y1), QPoint(x2, y2));
       
  5230 #endif
       
  5231 
       
  5232     int x, y;
       
  5233     int dx, dy, d, incrE, incrNE;
       
  5234 
       
  5235     dx = x2 - x1;
       
  5236     dy = y2 - y1;
       
  5237 
       
  5238     const int NSPANS = 256;
       
  5239     QT_FT_Span spans[NSPANS];
       
  5240     int current = 0;
       
  5241     bool ordered = true;
       
  5242 
       
  5243     if (dy == 0) {
       
  5244         // specialcase horizontal lines
       
  5245         if (y1 >= devRect.y1 && y1 < devRect.y2) {
       
  5246             int start = qMax(devRect.x1, qMin(x1, x2));
       
  5247             int stop = qMax(x1, x2) + 1;
       
  5248             int stop_clipped = qMin(devRect.x2, stop);
       
  5249             int len = stop_clipped - start;
       
  5250             if (style == LineDrawNormal && stop == stop_clipped)
       
  5251                 len--;
       
  5252             if (len > 0) {
       
  5253                 spans[0].x = ushort(start);
       
  5254                 spans[0].len = ushort(len);
       
  5255                 spans[0].y = y1;
       
  5256                 spans[0].coverage = 255;
       
  5257                 span_func(1, spans, data);
       
  5258             }
       
  5259         }
       
  5260         return;
       
  5261     } else if (dx == 0) {
       
  5262         // specialcase vertical lines
       
  5263         if (x1 >= devRect.x1 && x1 < devRect.x2) {
       
  5264             int start = qMax(devRect.y1, qMin(y1, y2));
       
  5265             int stop = qMax(y1, y2) + 1;
       
  5266             int stop_clipped = qMin(devRect.y2, stop);
       
  5267             int len = stop_clipped - start;
       
  5268             if (style == LineDrawNormal && stop == stop_clipped)
       
  5269                 len--;
       
  5270             // hw: create spans directly instead to possibly avoid clipping
       
  5271             if (len > 0)
       
  5272                 fillRect_normalized(QRect(x1, start, 1, len).normalized(), data, 0);
       
  5273         }
       
  5274         return;
       
  5275     }
       
  5276 
       
  5277 
       
  5278     if (qAbs(dx) >= qAbs(dy)) {       /* if x is the major axis: */
       
  5279 
       
  5280         if (x2 < x1) {  /* if coordinates are out of order */
       
  5281             qt_swap_int(x1, x2);
       
  5282             dx = -dx;
       
  5283 
       
  5284             qt_swap_int(y1, y2);
       
  5285             dy = -dy;
       
  5286         }
       
  5287 
       
  5288         int x_lower_limit = - 128;
       
  5289         if (x1 < x_lower_limit) {
       
  5290             int cy = dy * (x_lower_limit - x1) / dx + y1;
       
  5291             drawLine_midpoint_i(x_lower_limit, cy, x2, y2, span_func, data, style, devRect);
       
  5292             return;
       
  5293         }
       
  5294 
       
  5295         if (style == LineDrawNormal)
       
  5296             --x2;
       
  5297 
       
  5298         // In the loops below we increment before call the span function so
       
  5299         // we need to stop one pixel before
       
  5300         x2 = qMin(x2, devRect.x2 - 1);
       
  5301 
       
  5302         // completely clipped, so abort
       
  5303         if (x2 <= x1) {
       
  5304             return;
       
  5305         }
       
  5306 
       
  5307         int x = x1;
       
  5308         int y = y1;
       
  5309 
       
  5310         if (y2 <= y1)
       
  5311             ordered = false;
       
  5312 
       
  5313         {
       
  5314             const int index = (ordered ? current : NSPANS - 1 - current);
       
  5315             spans[index].coverage = 255;
       
  5316             spans[index].x = x;
       
  5317             spans[index].y = y;
       
  5318 
       
  5319             if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2)
       
  5320                 spans[index].len = 1;
       
  5321             else
       
  5322                 spans[index].len = 0;
       
  5323         }
       
  5324 
       
  5325         if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
       
  5326             y2 = qMin(y2, devRect.y2 - 1);
       
  5327 
       
  5328             incrE = dy * 2;
       
  5329             d = incrE - dx;
       
  5330             incrNE = (dy - dx) * 2;
       
  5331 
       
  5332             if (y > y2)
       
  5333                 goto flush_and_return;
       
  5334 
       
  5335             while (x < x2) {
       
  5336                 ++x;
       
  5337                 if (d > 0) {
       
  5338                     if (spans[current].len > 0)
       
  5339                         ++current;
       
  5340                     if (current == NSPANS) {
       
  5341                         span_func(NSPANS, spans, data);
       
  5342                         current = 0;
       
  5343                     }
       
  5344 
       
  5345                     ++y;
       
  5346                     d += incrNE;
       
  5347                     if (y > y2)
       
  5348                         goto flush_and_return;
       
  5349 
       
  5350                     spans[current].len = 0;
       
  5351                     spans[current].coverage = 255;
       
  5352                     spans[current].x = x;
       
  5353                     spans[current].y = y;
       
  5354                 } else {
       
  5355                     d += incrE;
       
  5356                     if (x == devRect.x1)
       
  5357                         spans[current].x = devRect.x1;
       
  5358                 }
       
  5359 
       
  5360                 if (x < devRect.x1 || y < devRect.y1)
       
  5361                     continue;
       
  5362 
       
  5363                 Q_ASSERT(x<devRect.x2);
       
  5364                 Q_ASSERT(y<devRect.y2);
       
  5365                 Q_ASSERT(spans[current].y == y);
       
  5366                 spans[current].len++;
       
  5367             }
       
  5368             if (spans[current].len > 0) {
       
  5369                 ++current;
       
  5370             }
       
  5371         } else {  // 0-45 and 180->225 (unit circle degrees)
       
  5372 
       
  5373             y1 = qMin(y1, devRect.y2 - 1);
       
  5374 
       
  5375             incrE = dy * 2;
       
  5376             d = incrE + dx;
       
  5377             incrNE = (dy + dx) * 2;
       
  5378 
       
  5379             if (y < devRect.y1)
       
  5380                 goto flush_and_return;
       
  5381 
       
  5382             while (x < x2) {
       
  5383                 ++x;
       
  5384                 if (d < 0) {
       
  5385                     if (spans[NSPANS - 1 - current].len > 0)
       
  5386                         ++current;
       
  5387                     if (current == NSPANS) {
       
  5388                         span_func(NSPANS, spans, data);
       
  5389                         current = 0;
       
  5390                     }
       
  5391 
       
  5392                     --y;
       
  5393                     d += incrNE;
       
  5394                     if (y < devRect.y1)
       
  5395                         goto flush_and_return;
       
  5396 
       
  5397                     const int index = NSPANS - 1 - current;
       
  5398                     spans[index].len = 0;
       
  5399                     spans[index].coverage = 255;
       
  5400                     spans[index].x = x;
       
  5401                     spans[index].y = y;
       
  5402                 } else {
       
  5403                     d += incrE;
       
  5404                     if (x == devRect.x1)
       
  5405                         spans[NSPANS - 1 - current].x = devRect.x1;
       
  5406                 }
       
  5407 
       
  5408                 if (x < devRect.x1 || y > y1)
       
  5409                     continue;
       
  5410 
       
  5411                 Q_ASSERT(x<devRect.x2 && y<devRect.y2);
       
  5412                 Q_ASSERT(spans[NSPANS - 1 - current].y == y);
       
  5413                 spans[NSPANS - 1 - current].len++;
       
  5414             }
       
  5415             if (spans[NSPANS - 1 - current].len > 0) {
       
  5416                 ++current;
       
  5417             }
       
  5418         }
       
  5419 
       
  5420     } else {
       
  5421 
       
  5422         // if y is the major axis:
       
  5423 
       
  5424         if (y2 < y1) {      /* if coordinates are out of order */
       
  5425             qt_swap_int(y1, y2);
       
  5426             dy = -dy;
       
  5427 
       
  5428             qt_swap_int(x1, x2);
       
  5429             dx = -dx;
       
  5430         }
       
  5431 
       
  5432         int y_lower_limit = - 128;
       
  5433         if (y1 < y_lower_limit) {
       
  5434             int cx = dx * (y_lower_limit - y1) / dy + x1;
       
  5435             drawLine_midpoint_i(cx, y_lower_limit, x2, y2, span_func, data, style, devRect);
       
  5436             return;
       
  5437         }
       
  5438 
       
  5439         if (style == LineDrawNormal)
       
  5440             --y2;
       
  5441 
       
  5442         // In the loops below we increment before call the span function so
       
  5443         // we need to stop one pixel before
       
  5444         y2 = qMin(y2, devRect.y2 - 1);
       
  5445 
       
  5446         // completely clipped, so abort
       
  5447         if (y2 <= y1) {
       
  5448             return;
       
  5449         }
       
  5450 
       
  5451         x = x1;
       
  5452         y = y1;
       
  5453 
       
  5454         if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) {
       
  5455             Q_ASSERT(x >= devRect.x1 && y >= devRect.y1 && x < devRect.x2 && y < devRect.y2);
       
  5456             if (current == NSPANS) {
       
  5457                 span_func(NSPANS, spans, data);
       
  5458                 current = 0;
       
  5459             }
       
  5460             spans[current].len = 1;
       
  5461             spans[current].coverage = 255;
       
  5462             spans[current].x = x;
       
  5463             spans[current].y = y;
       
  5464             ++current;
       
  5465         }
       
  5466 
       
  5467         if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
       
  5468             x2 = qMin(x2, devRect.x2 - 1);
       
  5469             incrE = dx * 2;
       
  5470             d = incrE - dy;
       
  5471             incrNE = (dx - dy) * 2;
       
  5472 
       
  5473             if (x > x2)
       
  5474                 goto flush_and_return;
       
  5475 
       
  5476             while (y < y2) {
       
  5477                 if (d > 0) {
       
  5478                     ++x;
       
  5479                     d += incrNE;
       
  5480                     if (x > x2)
       
  5481                         goto flush_and_return;
       
  5482                 } else {
       
  5483                     d += incrE;
       
  5484                 }
       
  5485                 ++y;
       
  5486                 if (x < devRect.x1 || y < devRect.y1)
       
  5487                     continue;
       
  5488                 Q_ASSERT(x<devRect.x2 && y<devRect.y2);
       
  5489                 if (current == NSPANS) {
       
  5490                     span_func(NSPANS, spans, data);
       
  5491                     current = 0;
       
  5492                 }
       
  5493                 spans[current].len = 1;
       
  5494                 spans[current].coverage = 255;
       
  5495                 spans[current].x = x;
       
  5496                 spans[current].y = y;
       
  5497                 ++current;
       
  5498             }
       
  5499         } else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
       
  5500             x1 = qMin(x1, devRect.x2 - 1);
       
  5501             incrE = dx * 2;
       
  5502             d = incrE + dy;
       
  5503             incrNE = (dx + dy) * 2;
       
  5504 
       
  5505             if (x < devRect.x1)
       
  5506                 goto flush_and_return;
       
  5507 
       
  5508             while (y < y2) {
       
  5509                 if (d < 0) {
       
  5510                     --x;
       
  5511                     d += incrNE;
       
  5512                     if (x < devRect.x1)
       
  5513                         goto flush_and_return;
       
  5514                 } else {
       
  5515                     d += incrE;
       
  5516                 }
       
  5517                 ++y;
       
  5518                 if (y < devRect.y1 || x > x1)
       
  5519                     continue;
       
  5520                 Q_ASSERT(x>=devRect.x1 && x<devRect.x2 && y>=devRect.y1 && y<devRect.y2);
       
  5521                 if (current == NSPANS) {
       
  5522                     span_func(NSPANS, spans, data);
       
  5523                     current = 0;
       
  5524                 }
       
  5525                 spans[current].len = 1;
       
  5526                 spans[current].coverage = 255;
       
  5527                 spans[current].x = x;
       
  5528                 spans[current].y = y;
       
  5529                 ++current;
       
  5530             }
       
  5531         }
       
  5532     }
       
  5533 flush_and_return:
       
  5534     if (current > 0)
       
  5535         span_func(current, ordered ? spans : spans + (NSPANS - current), data);
       
  5536 }
       
  5537 
       
  5538 static void offset_pattern(int offset, bool *inDash, int *dashIndex, int *currentOffset, const QVarLengthArray<qreal> &pattern)
       
  5539 {
       
  5540     while (offset--) {
       
  5541         if (--*currentOffset == 0) {
       
  5542             *inDash = !*inDash;
       
  5543             *dashIndex = ((*dashIndex + 1) % pattern.size());
       
  5544             *currentOffset = int(pattern[*dashIndex]);
       
  5545         }
       
  5546     }
       
  5547 }
       
  5548 
       
  5549 static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
       
  5550                                        QPen *pen,
       
  5551                                        ProcessSpans span_func, QSpanData *data,
       
  5552                                        LineDrawMode style, const QIntRect &devRect,
       
  5553                                        int *patternOffset)
       
  5554 {
       
  5555 #ifdef QT_DEBUG_DRAW
       
  5556     qDebug() << "   - drawLine_midpoint_dashed_i" << x1 << y1 << x2 << y2 << *patternOffset;
       
  5557 #endif
       
  5558 
       
  5559     int x, y;
       
  5560     int dx, dy, d, incrE, incrNE;
       
  5561 
       
  5562     dx = x2 - x1;
       
  5563     dy = y2 - y1;
       
  5564 
       
  5565     Q_ASSERT(*patternOffset >= 0);
       
  5566 
       
  5567     const QVector<qreal> penPattern = pen->dashPattern();
       
  5568     QVarLengthArray<qreal> pattern(penPattern.size());
       
  5569 
       
  5570     int patternLength = 0;
       
  5571     for (int i = 0; i < penPattern.size(); ++i)
       
  5572         patternLength += qMax<qreal>(1.0, (penPattern.at(i)));
       
  5573 
       
  5574     // pattern must be reversed if coordinates are out of order
       
  5575     int reverseLength = -1;
       
  5576     if (dy == 0 && x1 > x2)
       
  5577         reverseLength = x1 - x2;
       
  5578     else if (dx == 0 && y1 > y2)
       
  5579         reverseLength = y1 - y2;
       
  5580     else if (qAbs(dx) >= qAbs(dy) && x2 < x1) // x major axis
       
  5581         reverseLength = qAbs(dx);
       
  5582     else if (qAbs(dy) >= qAbs(dx) && y2 < y1) // y major axis
       
  5583         reverseLength = qAbs(dy);
       
  5584 
       
  5585     const bool reversed = (reverseLength > -1);
       
  5586     if (reversed) { // reverse pattern
       
  5587         for (int i = 0; i < penPattern.size(); ++i)
       
  5588             pattern[penPattern.size() - 1 - i] = qMax<qreal>(1.0, penPattern.at(i));
       
  5589 
       
  5590         *patternOffset = (patternLength - 1 - *patternOffset);
       
  5591         *patternOffset += patternLength - (reverseLength % patternLength);
       
  5592         *patternOffset = *patternOffset % patternLength;
       
  5593     } else {
       
  5594         for (int i = 0; i < penPattern.size(); ++i)
       
  5595             pattern[i] = qMax<qreal>(1.0, penPattern.at(i));
       
  5596     }
       
  5597 
       
  5598     int dashIndex = 0;
       
  5599     bool inDash = !reversed;
       
  5600     int currPattern = int(pattern[dashIndex]);
       
  5601 
       
  5602     // adjust pattern for offset
       
  5603     offset_pattern(*patternOffset, &inDash, &dashIndex, &currPattern, pattern);
       
  5604 
       
  5605     const int NSPANS = 256;
       
  5606     QT_FT_Span spans[NSPANS];
       
  5607     int current = 0;
       
  5608     bool ordered = true;
       
  5609 
       
  5610     if (dy == 0) {
       
  5611         // specialcase horizontal lines
       
  5612         if (y1 >= devRect.y1 && y1 < devRect.y2) {
       
  5613             int start_unclipped = qMin(x1, x2);
       
  5614             int start = qMax(devRect.x1, start_unclipped);
       
  5615             int stop = qMax(x1, x2) + 1;
       
  5616             int stop_clipped = qMin(devRect.x2, stop);
       
  5617             int len = stop_clipped - start;
       
  5618             if (style == LineDrawNormal && stop == stop_clipped)
       
  5619                 len--;
       
  5620 
       
  5621             // adjust pattern for starting offset
       
  5622             offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern);
       
  5623 
       
  5624             if (len > 0) {
       
  5625                 int x = start;
       
  5626                 while (x < stop_clipped) {
       
  5627                     if (current == NSPANS) {
       
  5628                         span_func(NSPANS, spans, data);
       
  5629                         current = 0;
       
  5630                     }
       
  5631                     const int dash = qMin(currPattern, stop_clipped - x);
       
  5632                     if (inDash) {
       
  5633                         spans[current].x = ushort(x);
       
  5634                         spans[current].len = ushort(dash);
       
  5635                         spans[current].y = y1;
       
  5636                         spans[current].coverage = 255;
       
  5637                         ++current;
       
  5638                     }
       
  5639                     if (dash < currPattern) {
       
  5640                         currPattern -= dash;
       
  5641                     } else {
       
  5642                         dashIndex = (dashIndex + 1) % pattern.size();
       
  5643                         currPattern = int(pattern[dashIndex]);
       
  5644                         inDash = !inDash;
       
  5645                     }
       
  5646                     x += dash;
       
  5647                 }
       
  5648             }
       
  5649         }
       
  5650         goto flush_and_return;
       
  5651     } else if (dx == 0) {
       
  5652         if (x1 >= devRect.x1 && x1 < devRect.x2) {
       
  5653             int start_unclipped = qMin(y1, y2);
       
  5654             int start = qMax(devRect.y1, start_unclipped);
       
  5655             int stop = qMax(y1, y2) + 1;
       
  5656             int stop_clipped = qMin(devRect.y2, stop);
       
  5657             if (style == LineDrawNormal && stop == stop_clipped)
       
  5658                 --stop;
       
  5659             else
       
  5660                 stop = stop_clipped;
       
  5661 
       
  5662             // adjust pattern for starting offset
       
  5663             offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern);
       
  5664 
       
  5665             // loop over dashes
       
  5666             int y = start;
       
  5667             while (y < stop) {
       
  5668                 const int dash = qMin(currPattern, stop - y);
       
  5669                 if (inDash) {
       
  5670                     for (int i = 0; i < dash; ++i) {
       
  5671                         if (current == NSPANS) {
       
  5672                             span_func(NSPANS, spans, data);
       
  5673                             current = 0;
       
  5674                         }
       
  5675                         spans[current].x = x1;
       
  5676                         spans[current].len = 1;
       
  5677                         spans[current].coverage = 255;
       
  5678                         spans[current].y = ushort(y + i);
       
  5679                         ++current;
       
  5680                     }
       
  5681                 }
       
  5682                 if (dash < currPattern) {
       
  5683                     currPattern -= dash;
       
  5684                 } else {
       
  5685                     dashIndex = (dashIndex + 1) % pattern.size();
       
  5686                     currPattern = int(pattern[dashIndex]);
       
  5687                     inDash = !inDash;
       
  5688                 }
       
  5689                 y += dash;
       
  5690             }
       
  5691         }
       
  5692         goto flush_and_return;
       
  5693     }
       
  5694 
       
  5695     if (qAbs(dx) >= qAbs(dy)) {       /* if x is the major axis: */
       
  5696 
       
  5697         if (x2 < x1) {  /* if coordinates are out of order */
       
  5698             qt_swap_int(x1, x2);
       
  5699             dx = -dx;
       
  5700 
       
  5701             qt_swap_int(y1, y2);
       
  5702             dy = -dy;
       
  5703         }
       
  5704 
       
  5705         if (style == LineDrawNormal)
       
  5706             --x2;
       
  5707 
       
  5708         // In the loops below we increment before call the span function so
       
  5709         // we need to stop one pixel before
       
  5710         x2 = qMin(x2, devRect.x2 - 1);
       
  5711 
       
  5712         // completely clipped, so abort
       
  5713         if (x2 <= x1)
       
  5714             goto flush_and_return;
       
  5715 
       
  5716         int x = x1;
       
  5717         int y = y1;
       
  5718 
       
  5719         if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) {
       
  5720             Q_ASSERT(x < devRect.x2);
       
  5721             if (inDash) {
       
  5722                 if (current == NSPANS) {
       
  5723                     span_func(NSPANS, spans, data);
       
  5724                     current = 0;
       
  5725                 }
       
  5726                 spans[current].len = 1;
       
  5727                 spans[current].coverage = 255;
       
  5728                 spans[current].x = x;
       
  5729                 spans[current].y = y;
       
  5730                 ++current;
       
  5731             }
       
  5732             if (--currPattern <= 0) {
       
  5733                 inDash = !inDash;
       
  5734                 dashIndex = (dashIndex + 1) % pattern.size();
       
  5735                 currPattern = int(pattern[dashIndex]);
       
  5736             }
       
  5737         }
       
  5738 
       
  5739         if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
       
  5740             y2 = qMin(y2, devRect.y2 - 1);
       
  5741 
       
  5742             incrE = dy * 2;
       
  5743             d = incrE - dx;
       
  5744             incrNE = (dy - dx) * 2;
       
  5745 
       
  5746             if (y > y2)
       
  5747                 goto flush_and_return;
       
  5748 
       
  5749             while (x < x2) {
       
  5750                 if (d > 0) {
       
  5751                     ++y;
       
  5752                     d += incrNE;
       
  5753                     if (y > y2)
       
  5754                         goto flush_and_return;
       
  5755                 } else {
       
  5756                     d += incrE;
       
  5757                 }
       
  5758                 ++x;
       
  5759 
       
  5760                 const bool skip = x < devRect.x1 || y < devRect.y1;
       
  5761                 Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
       
  5762                 if (inDash && !skip) {
       
  5763                     if (current == NSPANS) {
       
  5764                         span_func(NSPANS, spans, data);
       
  5765                         current = 0;
       
  5766                     }
       
  5767                     spans[current].len = 1;
       
  5768                     spans[current].coverage = 255;
       
  5769                     spans[current].x = x;
       
  5770                     spans[current].y = y;
       
  5771                     ++current;
       
  5772                 }
       
  5773                 if (--currPattern <= 0) {
       
  5774                     inDash = !inDash;
       
  5775                     dashIndex = (dashIndex + 1) % pattern.size();
       
  5776                     currPattern = int(pattern[dashIndex]);
       
  5777                 }
       
  5778             }
       
  5779         } else {  // 0-45 and 180->225 (unit circle degrees)
       
  5780             y1 = qMin(y1, devRect.y2 - 1);
       
  5781 
       
  5782             incrE = dy * 2;
       
  5783             d = incrE + dx;
       
  5784             incrNE = (dy + dx) * 2;
       
  5785 
       
  5786             if (y < devRect.y1)
       
  5787                 goto flush_and_return;
       
  5788 
       
  5789             while (x < x2) {
       
  5790                 if (d < 0) {
       
  5791                     if (current > 0) {
       
  5792                         span_func(current, spans, data);
       
  5793                         current = 0;
       
  5794                     }
       
  5795 
       
  5796                     --y;
       
  5797                     d += incrNE;
       
  5798                     if (y < devRect.y1)
       
  5799                         goto flush_and_return;
       
  5800                 } else {
       
  5801                     d += incrE;
       
  5802                 }
       
  5803                 ++x;
       
  5804 
       
  5805                 const bool skip = x < devRect.x1 || y > y1;
       
  5806                 Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
       
  5807                 if (inDash && !skip) {
       
  5808                     if (current == NSPANS) {
       
  5809                         span_func(NSPANS, spans, data);
       
  5810                         current = 0;
       
  5811                     }
       
  5812                     spans[current].len = 1;
       
  5813                     spans[current].coverage = 255;
       
  5814                     spans[current].x = x;
       
  5815                     spans[current].y = y;
       
  5816                     ++current;
       
  5817                 }
       
  5818                 if (--currPattern <= 0) {
       
  5819                     inDash = !inDash;
       
  5820                     dashIndex = (dashIndex + 1) % pattern.size();
       
  5821                     currPattern = int(pattern[dashIndex]);
       
  5822                 }
       
  5823             }
       
  5824         }
       
  5825     } else {
       
  5826 
       
  5827         // if y is the major axis:
       
  5828 
       
  5829         if (y2 < y1) {      /* if coordinates are out of order */
       
  5830             qt_swap_int(y1, y2);
       
  5831             dy = -dy;
       
  5832 
       
  5833             qt_swap_int(x1, x2);
       
  5834             dx = -dx;
       
  5835         }
       
  5836 
       
  5837         if (style == LineDrawNormal)
       
  5838             --y2;
       
  5839 
       
  5840         // In the loops below we increment before call the span function so
       
  5841         // we need to stop one pixel before
       
  5842         y2 = qMin(y2, devRect.y2 - 1);
       
  5843 
       
  5844         // completely clipped, so abort
       
  5845         if (y2 <= y1)
       
  5846             goto flush_and_return;
       
  5847 
       
  5848         x = x1;
       
  5849         y = y1;
       
  5850 
       
  5851         if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) {
       
  5852             Q_ASSERT(x < devRect.x2);
       
  5853             if (inDash) {
       
  5854                 if (current == NSPANS) {
       
  5855                     span_func(NSPANS, spans, data);
       
  5856                     current = 0;
       
  5857                 }
       
  5858                 spans[current].len = 1;
       
  5859                 spans[current].coverage = 255;
       
  5860                 spans[current].x = x;
       
  5861                 spans[current].y = y;
       
  5862                 ++current;
       
  5863             }
       
  5864             if (--currPattern <= 0) {
       
  5865                 inDash = !inDash;
       
  5866                 dashIndex = (dashIndex + 1) % pattern.size();
       
  5867                 currPattern = int(pattern[dashIndex]);
       
  5868             }
       
  5869         }
       
  5870 
       
  5871         if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
       
  5872             x2 = qMin(x2, devRect.x2 - 1);
       
  5873             incrE = dx * 2;
       
  5874             d = incrE - dy;
       
  5875             incrNE = (dx - dy) * 2;
       
  5876 
       
  5877             if (x > x2)
       
  5878                 goto flush_and_return;
       
  5879 
       
  5880             while (y < y2) {
       
  5881                 if (d > 0) {
       
  5882                     ++x;
       
  5883                     d += incrNE;
       
  5884                     if (x > x2)
       
  5885                         goto flush_and_return;
       
  5886                 } else {
       
  5887                     d += incrE;
       
  5888                 }
       
  5889                 ++y;
       
  5890                 const bool skip = x < devRect.x1 || y < devRect.y1;
       
  5891                 Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
       
  5892                 if (inDash && !skip) {
       
  5893                     if (current == NSPANS) {
       
  5894                         span_func(NSPANS, spans, data);
       
  5895                         current = 0;
       
  5896                     }
       
  5897                     spans[current].len = 1;
       
  5898                     spans[current].coverage = 255;
       
  5899                     spans[current].x = x;
       
  5900                     spans[current].y = y;
       
  5901                     ++current;
       
  5902                 }
       
  5903                 if (--currPattern <= 0) {
       
  5904                     inDash = !inDash;
       
  5905                     dashIndex = (dashIndex + 1) % pattern.size();
       
  5906                     currPattern = int(pattern[dashIndex]);
       
  5907                 }
       
  5908             }
       
  5909         } else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
       
  5910             x1 = qMin(x1, devRect.x2 - 1);
       
  5911             incrE = dx * 2;
       
  5912             d = incrE + dy;
       
  5913             incrNE = (dx + dy) * 2;
       
  5914 
       
  5915             if (x < devRect.x1)
       
  5916                 goto flush_and_return;
       
  5917 
       
  5918             while (y < y2) {
       
  5919                 if (d < 0) {
       
  5920                     --x;
       
  5921                     d += incrNE;
       
  5922                     if (x < devRect.x1)
       
  5923                         goto flush_and_return;
       
  5924                 } else {
       
  5925                     d += incrE;
       
  5926                 }
       
  5927                 ++y;
       
  5928                 const bool skip = y < devRect.y1 || x > x1;
       
  5929                 Q_ASSERT(skip || (x >= devRect.x1 && x < devRect.x2 && y < devRect.y2));
       
  5930                 if (inDash && !skip) {
       
  5931                     if (current == NSPANS) {
       
  5932                         span_func(NSPANS, spans, data);
       
  5933                         current = 0;
       
  5934                     }
       
  5935                     spans[current].len = 1;
       
  5936                     spans[current].coverage = 255;
       
  5937                     spans[current].x = x;
       
  5938                     spans[current].y = y;
       
  5939                     ++current;
       
  5940                 }
       
  5941                 if (--currPattern <= 0) {
       
  5942                     inDash = !inDash;
       
  5943                     dashIndex = (dashIndex + 1) % pattern.size();
       
  5944                     currPattern = int(pattern[dashIndex]);
       
  5945                 }
       
  5946             }
       
  5947         }
       
  5948     }
       
  5949 flush_and_return:
       
  5950     if (current > 0)
       
  5951         span_func(current, ordered ? spans : spans + (NSPANS - current), data);
       
  5952 
       
  5953     // adjust offset
       
  5954     if (reversed) {
       
  5955         *patternOffset = (patternLength - 1 - *patternOffset);
       
  5956     } else {
       
  5957         *patternOffset = 0;
       
  5958         for (int i = 0; i <= dashIndex; ++i)
       
  5959             *patternOffset += int(pattern[i]);
       
  5960         *patternOffset += patternLength - currPattern - 1;
       
  5961         *patternOffset = (*patternOffset % patternLength);
       
  5962     }
       
  5963 }
       
  5964 
       
  5965 /*!
       
  5966     \internal
       
  5967     \a x and \a y is relative to the midpoint of \a rect.
       
  5968 */
       
  5969 static inline void drawEllipsePoints(int x, int y, int length,
       
  5970                                      const QRect &rect,
       
  5971                                      const QRect &clip,
       
  5972                                      ProcessSpans pen_func, ProcessSpans brush_func,
       
  5973                                      QSpanData *pen_data, QSpanData *brush_data)
       
  5974 {
       
  5975     if (length == 0)
       
  5976         return;
       
  5977 
       
  5978     QT_FT_Span outline[4];
       
  5979     const int midx = rect.x() + (rect.width() + 1) / 2;
       
  5980     const int midy = rect.y() + (rect.height() + 1) / 2;
       
  5981 
       
  5982     x = x + midx;
       
  5983     y = midy - y;
       
  5984 
       
  5985     // topleft
       
  5986     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
       
  5987     outline[0].len = qMin(length, x - outline[0].x);
       
  5988     outline[0].y = y;
       
  5989     outline[0].coverage = 255;
       
  5990 
       
  5991     // topright
       
  5992     outline[1].x = x;
       
  5993     outline[1].len = length;
       
  5994     outline[1].y = y;
       
  5995     outline[1].coverage = 255;
       
  5996 
       
  5997     // bottomleft
       
  5998     outline[2].x = outline[0].x;
       
  5999     outline[2].len = outline[0].len;
       
  6000     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
       
  6001     outline[2].coverage = 255;
       
  6002 
       
  6003     // bottomright
       
  6004     outline[3].x = x;
       
  6005     outline[3].len = length;
       
  6006     outline[3].y = outline[2].y;
       
  6007     outline[3].coverage = 255;
       
  6008 
       
  6009     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
       
  6010         QT_FT_Span fill[2];
       
  6011 
       
  6012         // top fill
       
  6013         fill[0].x = outline[0].x + outline[0].len - 1;
       
  6014         fill[0].len = qMax(0, outline[1].x - fill[0].x);
       
  6015         fill[0].y = outline[1].y;
       
  6016         fill[0].coverage = 255;
       
  6017 
       
  6018         // bottom fill
       
  6019         fill[1].x = outline[2].x + outline[2].len - 1;
       
  6020         fill[1].len = qMax(0, outline[3].x - fill[1].x);
       
  6021         fill[1].y = outline[3].y;
       
  6022         fill[1].coverage = 255;
       
  6023 
       
  6024         int n = (fill[0].y >= fill[1].y ? 1 : 2);
       
  6025         n = qt_intersect_spans(fill, n, clip);
       
  6026         if (n > 0)
       
  6027             brush_func(n, fill, brush_data);
       
  6028     }
       
  6029     if (pen_func) {
       
  6030         int n = (outline[1].y >= outline[2].y ? 2 : 4);
       
  6031         n = qt_intersect_spans(outline, n, clip);
       
  6032         if (n > 0)
       
  6033             pen_func(n, outline, pen_data);
       
  6034     }
       
  6035 }
       
  6036 
       
  6037 /*!
       
  6038     \internal
       
  6039     Draws an ellipse using the integer point midpoint algorithm.
       
  6040 */
       
  6041 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
       
  6042                                    ProcessSpans pen_func, ProcessSpans brush_func,
       
  6043                                    QSpanData *pen_data, QSpanData *brush_data)
       
  6044 {
       
  6045 #ifdef FLOATING_POINT_BUGGY_OR_NO_FPU // no fpu, so use fixed point
       
  6046     const QFixed a = QFixed(rect.width()) >> 1;
       
  6047     const QFixed b = QFixed(rect.height()) >> 1;
       
  6048     QFixed d = b*b - (a*a*b) + ((a*a) >> 2);
       
  6049 #else
       
  6050     const qreal a = qreal(rect.width()) / 2;
       
  6051     const qreal b = qreal(rect.height()) / 2;
       
  6052     qreal d = b*b - (a*a*b) + 0.25*a*a;
       
  6053 #endif
       
  6054 
       
  6055     int x = 0;
       
  6056     int y = (rect.height() + 1) / 2;
       
  6057     int startx = x;
       
  6058 
       
  6059     // region 1
       
  6060     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
       
  6061         if (d < 0) { // select E
       
  6062             d += b*b*(2*x + 3);
       
  6063             ++x;
       
  6064         } else {     // select SE
       
  6065             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
       
  6066             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
       
  6067                               pen_func, brush_func, pen_data, brush_data);
       
  6068             startx = ++x;
       
  6069             --y;
       
  6070         }
       
  6071     }
       
  6072     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
       
  6073                       pen_func, brush_func, pen_data, brush_data);
       
  6074 
       
  6075     // region 2
       
  6076 #ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
       
  6077     d = b*b*(x + (QFixed(1) >> 1))*(x + (QFixed(1) >> 1))
       
  6078         + a*a*((y - 1)*(y - 1) - b*b);
       
  6079 #else
       
  6080     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
       
  6081 #endif
       
  6082     const int miny = rect.height() & 0x1;
       
  6083     while (y > miny) {
       
  6084         if (d < 0) { // select SE
       
  6085             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
       
  6086             ++x;
       
  6087         } else {     // select S
       
  6088             d += a*a*(-2*y + 3);
       
  6089         }
       
  6090         --y;
       
  6091         drawEllipsePoints(x, y, 1, rect, clip,
       
  6092                           pen_func, brush_func, pen_data, brush_data);
       
  6093     }
       
  6094 }
       
  6095 
       
  6096 /*!
       
  6097     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
       
  6098     \overload
       
  6099 
       
  6100     Draws the first \a pointCount points in the buffer \a points
       
  6101 
       
  6102     The default implementation converts the first \a pointCount QPoints in \a points
       
  6103     to QPointFs and calls the floating point version of drawPoints.
       
  6104 */
       
  6105 
       
  6106 /*!
       
  6107     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
       
  6108     \overload
       
  6109 
       
  6110     Reimplement this function to draw the largest ellipse that can be
       
  6111     contained within rectangle \a rect.
       
  6112 */
       
  6113 
       
  6114 #ifdef QT_DEBUG_DRAW
       
  6115 void dumpClip(int width, int height, const QClipData *clip)
       
  6116 {
       
  6117     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
       
  6118     clipImg.fill(0xffff0000);
       
  6119 
       
  6120     int x0 = width;
       
  6121     int x1 = 0;
       
  6122     int y0 = height;
       
  6123     int y1 = 0;
       
  6124 
       
  6125     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
       
  6126 
       
  6127     for (int i = 0; i < clip->count; ++i) {
       
  6128         const QSpan *span = ((QClipData *) clip)->spans() + i;
       
  6129         for (int j = 0; j < span->len; ++j)
       
  6130             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
       
  6131         x0 = qMin(x0, int(span->x));
       
  6132         x1 = qMax(x1, int(span->x + span->len - 1));
       
  6133 
       
  6134         y0 = qMin(y0, int(span->y));
       
  6135         y1 = qMax(y1, int(span->y));
       
  6136     }
       
  6137 
       
  6138     static int counter = 0;
       
  6139 
       
  6140     Q_ASSERT(y0 >= 0);
       
  6141     Q_ASSERT(x0 >= 0);
       
  6142     Q_ASSERT(y1 >= 0);
       
  6143     Q_ASSERT(x1 >= 0);
       
  6144 
       
  6145     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
       
  6146     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
       
  6147 }
       
  6148 #endif
       
  6149 
       
  6150 
       
  6151 QT_END_NAMESPACE