src/gui/painting/qpaintengine_raster.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #define QT_FT_BEGIN_HEADER
00025 #define QT_FT_END_HEADER
00026 #include <private/qrasterdefs_p.h>
00027 #include <private/qgrayraster_p.h>
00028 #include <private/qblackraster_p.h>
00029 
00030 #include <qpainterpath.h>
00031 #include <qdebug.h>
00032 #include <qhash.h>
00033 #include <qlabel.h>
00034 #include <qbitmap.h>
00035 
00036 #include <private/qmath_p.h>
00037 
00038 #include <private/qdatabuffer_p.h>
00039 #include <private/qpainter_p.h>
00040 #include <private/qtextengine_p.h>
00041 #include <private/qpixmap_p.h>
00042 #include <private/qfontengine_p.h>
00043 #include <private/qpolygonclipper_p.h>
00044 
00045 #include "qpaintengine_raster_p.h"
00046 #include "qbezier_p.h"
00047 
00048 #if defined(Q_WS_X11)
00049 #  include <qwidget.h>
00050 #  include <qx11info_x11.h>
00051 #  include <X11/Xlib.h>
00052 #  include <X11/Xutil.h>
00053 #elif defined(Q_WS_WIN)
00054 #  include <qt_windows.h>
00055 #  include <qvarlengtharray.h>
00056 #  include <private/qfontengine_p.h>
00057 #elif defined(Q_WS_MAC)
00058 #  include <private/qt_mac_p.h>
00059 #  if Q_BYTE_ORDER == Q_BIG_ENDIAN
00060 #    define BITMAPS_ARE_MSB
00061 #  endif
00062 #endif
00063 
00064 #if defined(Q_WS_WIN64)
00065 #  include <malloc.h>
00066 #endif
00067 #include <limits.h>
00068 
00069 
00070 #if defined(Q_WS_WIN)
00071 #  ifndef SPI_GETFONTSMOOTHINGTYPE
00072 #    define SPI_GETFONTSMOOTHINGTYPE 0x200A
00073 #  endif
00074 
00075 #  ifndef FE_FONTSMOOTHINGCLEARTYPE
00076 #    define FE_FONTSMOOTHINGCLEARTYPE 0x0002
00077 #  endif
00078 #endif
00079 
00080 #define qreal_to_fixed_26_6(f) (int(f * 64))
00081 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
00082 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
00083 
00084 #ifdef Q_WS_WIN
00085 void qt_draw_text_item(const QPointF &point, const QTextItemInt &ti, HDC hdc,
00086                        bool convertToText, const QMatrix &xform, const QPointF &topLeft);
00087 #endif
00088 
00089 // #define QT_DEBUG_DRAW
00090 // #define QT_DEBUG_CONVERT
00091 
00092 /********************************************************************************
00093  * Span functions
00094  */
00095 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
00096 static void qt_span_clip(int count, const QSpan *spans, void *userData);
00097 
00098 struct ClipData
00099 {
00100     QClipData *oldClip;
00101     QClipData *newClip;
00102     Qt::ClipOperation operation;
00103 };
00104 
00105 enum LineDrawMode {
00106     LineDrawClipped,
00107     LineDrawNormal,
00108     LineDrawIncludeLastPixel
00109 };
00110 
00111 static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
00112                                 LineDrawMode style, const QRect &devRect);
00113 static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
00114                                        QPen *pen, ProcessSpans span_func, QSpanData *data,
00115                                        LineDrawMode style, const QRect &devRect,
00116                                        int *patternOffset);
00117 // static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2,
00118 //                                 ProcessSpans span_func, QSpanData *data,
00119 //                                 LineDrawMode style, const QRect &devRect);
00120 
00121 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
00122                                    ProcessSpans pen_func, ProcessSpans brush_func,
00123                                    QSpanData *pen_data, QSpanData *brush_data);
00124 
00125 // This limitations comes from qgrayraster.c. Any higher and
00126 // rasterization of shapes will produce incorrect results.
00127 const int QT_RASTER_COORD_LIMIT = 16385;
00128 
00129 struct QRasterFloatPoint {
00130     qreal x;
00131     qreal y;
00132 };
00133 
00134 /********************************************************************************
00135  * class QFTOutlineMapper
00136  *
00137  * Used to map between QPainterPath and the QT_FT_Outline structure used by the
00138  * freetype scanconvertor.
00139  *
00140  * The outline mapper uses a path iterator to get points from the path,
00141  * so that it is possible to transform the points as they are converted. The
00142  * callback can be a noop, translate or full-fledged xform. (Tests indicated
00143  * that using a C callback was low cost).
00144  */
00145 class QFTOutlineMapper
00146 {
00147 public:
00148 
00154     void setMatrix(const QMatrix &m, uint txop)
00155     {
00156         m_m11 = m.m11();
00157         m_m12 = m.m12();
00158         m_m21 = m.m21();
00159         m_m22 = m.m22();
00160         m_dx = m.dx();
00161         m_dy = m.dy();
00162         m_txop = txop;
00163     }
00164 
00165     void beginOutline(Qt::FillRule fillRule)
00166     {
00167 #ifdef QT_DEBUG_CONVERT
00168         printf("QFTOutlineMapper::beginOutline rule=%d\n", fillRule);
00169 #endif
00170         m_valid = true;
00171         m_elements.reset();
00172         m_elements_dev.reset();
00173         m_element_types.reset();
00174         m_points.reset();
00175         m_tags.reset();
00176         m_contours.reset();
00177         m_outline.flags = fillRule == Qt::WindingFill
00178                           ? QT_FT_OUTLINE_NONE
00179                           : QT_FT_OUTLINE_EVEN_ODD_FILL;
00180         m_subpath_start = 0;
00181     }
00182 
00183     void endOutline();
00184 
00185     void clipElements(const QPointF *points, const QPainterPath::ElementType *types, int count);
00186 
00187     void convertElements(const QPointF *points, const QPainterPath::ElementType *types, int count);
00188 
00189     inline void moveTo(const QPointF &pt) {
00190 #ifdef QT_DEBUG_CONVERT
00191         printf("QFTOutlineMapper::moveTo() (%f, %f)\n", pt.x(), pt.y());
00192 #endif
00193         closeSubpath();
00194         m_subpath_start = m_elements.size();
00195         m_elements << pt;
00196         m_element_types << QPainterPath::MoveToElement;
00197     }
00198 
00199     inline void lineTo(const QPointF &pt) {
00200 #ifdef QT_DEBUG_CONVERT
00201         printf("QFTOutlineMapper::lineTo() (%f, %f)\n", pt.x(), pt.y());
00202 #endif
00203         m_elements.add(pt);
00204         m_element_types << QPainterPath::LineToElement;
00205     }
00206 
00207     inline void curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep) {
00208 #ifdef QT_DEBUG_CONVERT
00209         printf("QFTOutlineMapper::curveTo() (%f, %f)\n", ep.x(), ep.y());
00210 #endif
00211         m_elements << cp1 << cp2 << ep;
00212         m_element_types << QPainterPath::CurveToElement
00213                         << QPainterPath::CurveToDataElement
00214                         << QPainterPath::CurveToDataElement;
00215     }
00216 
00217     inline void closeSubpath() {
00218         int element_count = m_elements.size();
00219         if (element_count > 0) {
00220             if (m_elements.at(element_count-1) != m_elements.at(m_subpath_start)) {
00221 #ifdef QT_DEBUG_CONVERT
00222                 printf(" - implicitly closing\n");
00223 #endif
00224                 // Put the object on the stack to avoid the odd case where
00225                 // lineTo reallocs the databuffer and the QPointF & will
00226                 // be invalidated.
00227                 QPointF pt = m_elements.at(m_subpath_start);
00228                 lineTo(pt);
00229             }
00230         }
00231     }
00232 
00233     QT_FT_Outline *outline() {
00234         if (m_valid)
00235             return &m_outline;
00236         return 0;
00237     }
00238 
00239     QT_FT_Outline *convertPath(const QPainterPath &path)
00240     {
00241         Q_ASSERT(!path.isEmpty());
00242         int elmCount = path.elementCount();
00243 #ifdef QT_DEBUG_CONVERT
00244         printf("QFTOutlineMapper::convertPath(), size=%d\n", elmCount);
00245 #endif
00246         beginOutline(path.fillRule());
00247 
00248         for (int index=0; index<elmCount; ++index) {
00249             const QPainterPath::Element &elm = path.elementAt(index);
00250 
00251             switch (elm.type) {
00252 
00253             case QPainterPath::MoveToElement:
00254                 if (index == elmCount - 1)
00255                     continue;
00256                 moveTo(elm);
00257                 break;
00258 
00259             case QPainterPath::LineToElement:
00260                 lineTo(elm);
00261                 break;
00262 
00263             case QPainterPath::CurveToElement:
00264                 curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
00265                 index += 2;
00266                 break;
00267 
00268             default:
00269                 break; // This will never hit..
00270             }
00271         }
00272 
00273         endOutline();
00274         return outline();
00275     }
00276 
00277 public:
00278     QDataBuffer<QPainterPath::ElementType> m_element_types;
00279     QDataBuffer<QPointF> m_elements;
00280     QDataBuffer<QPointF> m_elements_dev;
00281     QDataBuffer<QT_FT_Vector> m_points;
00282     QDataBuffer<char> m_tags;
00283     QDataBuffer<int> m_contours;
00284 
00285     QPolygonClipper<QRasterFloatPoint, QRasterFloatPoint, qreal> m_clipper;
00286     QDataBuffer<QPointF> m_polygon_dev;
00287 
00288     QT_FT_Outline m_outline;
00289     uint m_txop;
00290 
00291     int m_subpath_start;
00292 
00293     // Matrix
00294     qreal m_m11;
00295     qreal m_m12;
00296     qreal m_m21;
00297     qreal m_m22;
00298     qreal m_dx;
00299     qreal m_dy;
00300 
00301     bool m_valid;
00302 };
00303 
00304 void QFTOutlineMapper::endOutline()
00305 {
00306     closeSubpath();
00307 
00308     int element_count = m_elements.size();
00309     const QPointF *elements;
00310 
00311     // Transform the outline
00312     if (m_txop == QPainterPrivate::TxNone) {
00313         elements = m_elements.data();
00314     } else {
00315         if (m_txop == QPainterPrivate::TxTranslate) {
00316             for (int i=0; i<m_elements.size(); ++i) {
00317                 const QPointF &e = m_elements.at(i);
00318                 m_elements_dev << QPointF(e.x() + m_dx, e.y() + m_dy);
00319             }
00320         } else if (m_txop == QPainterPrivate::TxScale) {
00321             for (int i=0; i<m_elements.size(); ++i) {
00322                 const QPointF &e = m_elements.at(i);
00323                 m_elements_dev << QPointF(m_m11 * e.x() + m_dx, m_m22 * e.y() + m_dy);
00324             }
00325         } else {
00326             for (int i=0; i<m_elements.size(); ++i) {
00327                 const QPointF &e = m_elements.at(i);
00328                 m_elements_dev << QPointF(m_m11 * e.x() + m_m21 * e.y() + m_dx,
00329                                           m_m22 * e.y() + m_m12 * e.x() + m_dy);
00330             }
00331         }
00332         elements = m_elements_dev.data();
00333     }
00334 
00335     // Check for out of dev bounds...
00336     const QPointF *last_element = elements + element_count;
00337     const QPointF *e = elements;
00338     bool do_clip = false;
00339     while (e < last_element) {
00340         if (e->x() < -QT_RASTER_COORD_LIMIT
00341             || e->x() > QT_RASTER_COORD_LIMIT
00342             || e->y() < -QT_RASTER_COORD_LIMIT
00343             || e->y() > QT_RASTER_COORD_LIMIT) {
00344             do_clip = true;
00345             break;
00346         }
00347         ++e;
00348     }
00349 
00350     if (do_clip) {
00351         clipElements(elements, m_element_types.data(), element_count);
00352     } else {
00353         convertElements(elements, m_element_types.data(), element_count);
00354     }
00355 }
00356 
00357 void QFTOutlineMapper::convertElements(const QPointF *elements,
00358                                        const QPainterPath::ElementType *types,
00359                                        int element_count)
00360 {
00361     // Translate into FT coords
00362     const QPointF *e = elements;
00363     for (int i=0; i<element_count; ++i) {
00364         switch (*types) {
00365         case QPainterPath::MoveToElement:
00366             {
00367                 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
00368                                           qreal_to_fixed_26_6(e->y()) };
00369                 if (i != 0)
00370                     m_contours << m_points.size() - 1;
00371                 m_points << pt_fixed;
00372                 m_tags <<  QT_FT_CURVE_TAG_ON;
00373             }
00374             break;
00375 
00376         case QPainterPath::LineToElement:
00377             {
00378                 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
00379                                           qreal_to_fixed_26_6(e->y()) };
00380                 m_points << pt_fixed;
00381                 m_tags << QT_FT_CURVE_TAG_ON;
00382             }
00383             break;
00384 
00385         case QPainterPath::CurveToElement:
00386             {
00387                 QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
00388                                            qreal_to_fixed_26_6(e->y()) };
00389                 ++e;
00390                 QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
00391                                            qreal_to_fixed_26_6((e)->y()) };
00392                 ++e;
00393                 QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
00394                                           qreal_to_fixed_26_6((e)->y()) };
00395 
00396                 m_points << cp1_fixed << cp2_fixed << ep_fixed;
00397                 m_tags << QT_FT_CURVE_TAG_CUBIC
00398                        << QT_FT_CURVE_TAG_CUBIC
00399                        << QT_FT_CURVE_TAG_ON;
00400 
00401                 types += 2;
00402                 i += 2;
00403             }
00404             break;
00405         default:
00406             break;
00407         }
00408         ++types;
00409         ++e;
00410     }
00411 
00412     // close the very last subpath
00413     m_contours << m_points.size() - 1;
00414 
00415     m_outline.n_contours = m_contours.size();
00416     m_outline.n_points = m_points.size();
00417 
00418     m_outline.points = m_points.data();
00419     m_outline.tags = m_tags.data();
00420     m_outline.contours = m_contours.data();
00421 
00422 #ifdef QT_DEBUG_CONVERT
00423     printf("QFTOutlineMapper::endOutline\n");
00424 
00425     printf(" - contours: %d\n", m_outline.n_contours);
00426     for (int i=0; i<m_outline.n_contours; ++i) {
00427         printf("   - %d\n", m_outline.contours[i]);
00428     }
00429 
00430     printf(" - points: %d\n", m_outline.n_points);
00431     for (int i=0; i<m_outline.n_points; ++i) {
00432         printf("   - %d -- %.2f, %.2f, (%d, %d)\n", i,
00433                m_outline.points[i].x / 64.0,
00434                m_outline.points[i].y / 64.0,
00435                m_outline.points[i], m_outline.points[i]);
00436     }
00437 #endif
00438 }
00439 
00440 void QFTOutlineMapper::clipElements(const QPointF *elements,
00441                                     const QPainterPath::ElementType *types,
00442                                     int element_count)
00443 {
00444     // We could save a bit of time by actually implementing them fully
00445     // instead of going through convenience functionallity, but since
00446     // this part of code hardly every used, it shouldn't matter.
00447 
00448     QPainterPath path;
00449     for (int i=0; i<element_count; ++i) {
00450         switch (types[i]) {
00451         case QPainterPath::MoveToElement:
00452             path.moveTo(elements[i]);
00453             break;
00454 
00455         case QPainterPath::LineToElement:
00456             path.lineTo(elements[i]);
00457             break;
00458 
00459         case QPainterPath::CurveToElement:
00460             path.cubicTo(elements[i], elements[i+1], elements[i+2]);
00461             i += 2;
00462             break;
00463         default:
00464             break;
00465         }
00466     }
00467 
00468     QPolygonF polygon = path.toFillPolygon();
00469     QPointF *clipped_points;
00470     int clipped_count;
00471 
00472     m_clipper.clipPolygon((QRasterFloatPoint *) polygon.constData(), polygon.size(),
00473                           ((QRasterFloatPoint **) &clipped_points), &clipped_count, true);
00474 
00475 #ifdef QT_DEBUG_CONVERT
00476     printf(" - shape was clipped\n");
00477     for (int i=0; i<clipped_count; ++i) {
00478         printf("   - %.2f, -%.2f\n", clipped_points[i].x(), clipped_points[i].y());
00479     }
00480 #endif
00481 
00482     if (!clipped_count) {
00483         m_valid = false;
00484         return;
00485     }
00486 
00487     QPainterPath::ElementType *point_types = new QPainterPath::ElementType[clipped_count];
00488     point_types[0] = QPainterPath::MoveToElement;
00489     for (int i=0; i<clipped_count; ++i) point_types[i] = QPainterPath::LineToElement;
00490     convertElements(clipped_points, point_types, clipped_count);
00491     delete[] point_types;
00492 }
00493 
00494 
00495 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
00496 {
00497     ((QFTOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
00498 }
00499 
00500 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
00501 {
00502     ((QFTOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
00503 }
00504 
00505 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
00506                              qfixed c2x, qfixed c2y,
00507                              qfixed ex, qfixed ey,
00508                              void *data)
00509 {
00510     ((QFTOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
00511                                          QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
00512                                          QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
00513 }
00514 
00515 
00516 #if !defined(QT_NO_DEBUG) && 0
00517 static void qt_debug_path(const QPainterPath &path)
00518 {
00519     const char *names[] = {
00520         "MoveTo     ",
00521         "LineTo     ",
00522         "CurveTo    ",
00523         "CurveToData"
00524     };
00525 
00526     printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
00527     for (int i=0; i<path.elementCount(); ++i) {
00528         const QPainterPath::Element &e = path.elementAt(i);
00529         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
00530         printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
00531     }
00532 }
00533 #endif
00534 
00535 
00580 QRasterPaintEngine::QRasterPaintEngine()
00581     : QPaintEngine(*(new QRasterPaintEnginePrivate),
00582                    QPaintEngine::PaintEngineFeatures(AllFeatures)
00583         )
00584 {
00585     init();
00586 }
00587 
00591 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd)
00592     : QPaintEngine(dd, QPaintEngine::PaintEngineFeatures(AllFeatures))
00593 {
00594     init();
00595 }
00596 
00597 void QRasterPaintEngine::init()
00598 {
00599     Q_D(QRasterPaintEngine);
00600 
00601     d->rasterPoolSize = 4096;
00602     d->rasterPoolBase =
00603 #if defined(Q_WS_WIN64)
00604         (unsigned char *) _aligned_malloc(d->rasterPoolSize, __alignof(void*));
00605 #else
00606         (unsigned char *) malloc(d->rasterPoolSize);
00607 #endif
00608 
00609     // The antialiasing raster.
00610     d->grayRaster = new QT_FT_Raster;
00611     qt_ft_grays_raster.raster_new(0, d->grayRaster);
00612     qt_ft_grays_raster.raster_reset(*d->grayRaster, d->rasterPoolBase, d->rasterPoolSize);
00613 
00614     // Initialize the standard raster.
00615     d->blackRaster = new QT_FT_Raster;
00616     qt_ft_standard_raster.raster_new(0, d->blackRaster);
00617     qt_ft_standard_raster.raster_reset(*d->blackRaster, d->rasterPoolBase, d->rasterPoolSize);
00618 
00619     d->rasterBuffer = new QRasterBuffer();
00620 #ifdef Q_WS_WIN
00621     d->fontRasterBuffer = new QRasterBuffer();
00622 #endif
00623     d->outlineMapper = new QFTOutlineMapper;
00624 
00625     d->dashStroker = 0;
00626 
00627     d->flushOnEnd = true;
00628 
00629     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
00630     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
00631     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
00632     d->dashStroker = 0;
00633 }
00634 
00638 QRasterPaintEngine::~QRasterPaintEngine()
00639 {
00640     Q_D(QRasterPaintEngine);
00641 
00642 #if defined(Q_WS_WIN64)
00643     _aligned_free(d->rasterPoolBase);
00644 #else
00645     free(d->rasterPoolBase);
00646 #endif
00647 
00648     qt_ft_grays_raster.raster_done(*d->grayRaster);
00649     delete d->grayRaster;
00650 
00651     qt_ft_standard_raster.raster_done(*d->blackRaster);
00652     delete d->blackRaster;
00653 
00654 
00655     delete d->rasterBuffer;
00656     delete d->outlineMapper;
00657 #ifdef Q_WS_WIN
00658     delete d->fontRasterBuffer;
00659 #endif
00660 
00661     delete d->dashStroker;
00662 }
00663 
00667 bool QRasterPaintEngine::begin(QPaintDevice *device)
00668 {
00669     Q_D(QRasterPaintEngine);
00670 
00671     // ####### move to QApp
00672     qInitDrawhelperAsm();
00673     d->deviceDepth = device->depth();
00674     d->antialiased = false;
00675     d->bilinear = false;
00676     d->mono_surface = false;
00677     d->fast_pen = true;
00678     d->int_xform = true;
00679     d->user_clip_enabled = false;
00680     d->opacity = 256;
00681 
00682     d->inverseScale = qreal(1);
00683 
00684 #if defined(Q_WS_WIN)
00685     d->clear_type_text = false;
00686     QT_WA({
00687         UINT result;
00688         BOOL ok;
00689         ok = SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
00690         if (ok)
00691             d->clear_type_text = (result == FE_FONTSMOOTHINGCLEARTYPE);
00692     }, {
00693         UINT result;
00694         BOOL ok;
00695         ok = SystemParametersInfoA(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
00696         if (ok)
00697             d->clear_type_text = (result == FE_FONTSMOOTHINGCLEARTYPE);
00698     });
00699 #endif
00700 
00701     d->rasterBuffer->init();
00702 
00703 #if defined(Q_WS_WIN)
00704     d->fontRasterBuffer->setupHDC(d->clear_type_text);
00705 #endif
00706 
00707     d->deviceRect = QRect(0, 0, device->width(), device->height());
00708 
00709 
00710     gccaps &= ~PorterDuff;
00711 
00712     // reset paintevent clip
00713     d->baseClip = QPainterPath();
00714     if (device->devType() == QInternal::Widget) {
00715         QRegion sysClip = systemClip();
00716         if (!sysClip.isEmpty()) {
00717             d->baseClip.addRegion(sysClip);
00718             d->deviceRect = sysClip.boundingRect();
00719             // Shift the baseclip to absolute
00720             d->baseClip = d->baseClip * QMatrix(1, 0, 0, 1,
00721                                                 -d->deviceRect.x(),
00722                                                 -d->deviceRect.y());
00723         }
00724         gccaps &= ~PaintOutsidePaintEvent;
00725     }
00726 #if defined(Q_WS_QWS)
00727     else if (device->devType() == QInternal::Pixmap) {
00728         // Only embedded uses system clipping on pixmaps
00729         QRegion sysClip = systemClip();
00730         if (!sysClip.isEmpty())
00731             d->baseClip.addRegion(sysClip);
00732     }
00733 #endif
00734     else {
00735         QRegion sysClip = systemClip();
00736         if (!sysClip.isEmpty()) {
00737             d->baseClip.addRegion(sysClip);
00738         }
00739     }
00740 
00741 #if defined(Q_WS_WIN) || defined(Q_WS_QWS)
00742     if (device->devType() == QInternal::Pixmap) {
00743         QPixmap *pixmap = static_cast<QPixmap *>(device);
00744         if (pixmap->isNull()) {
00745             qWarning("Cannot paint on a null pixmap");
00746             return false;
00747         }
00748         QPixmapData *data = static_cast<QPixmap *>(device)->data;
00749         device = &data->image;
00750     }
00751 #elif defined(Q_WS_MAC)
00752     if (device->devType() == QInternal::Pixmap) {
00753         QPixmap *pixmap = static_cast<QPixmap *>(device);
00754         if (pixmap->isNull()) {
00755             qWarning("Cannot paint on a null pixmap");
00756             return false;
00757         }
00758         d->rasterBuffer->prepare(pixmap);
00759     }
00760 #endif
00761 
00762     if (device->devType() == QInternal::Image) {
00763         QImage *image = static_cast<QImage *>(device);
00764         int format = image->format();
00765         d->flushOnEnd = false;
00766 
00767         d->rasterBuffer->prepare(image);
00768         if (format == QImage::Format_MonoLSB) {
00769             d->mono_surface = true;
00770         } else if (format == QImage::Format_Mono) {
00771             d->mono_surface = true;
00772         } else if (format == QImage::Format_RGB32) {
00773             ;
00774         } else if (format == QImage::Format_ARGB32_Premultiplied) {
00775             gccaps |= PorterDuff;
00776         } else if (format == QImage::Format_ARGB32) {
00777             gccaps |= PorterDuff;
00778 #ifdef Q_WS_QWS
00779         } else if (format == QImage::Format_RGB16) {
00780             ;
00781 #endif
00782         } else {
00783             qWarning("QRasterPaintEngine::begin: Unsupported image format (%d)", format);
00784             return false;
00785         }
00786 #ifdef Q_WS_QWS
00787     } else if (device->devType() == QInternal::CustomRaster) {
00788         QCustomRasterPaintDevice *dev = static_cast<QCustomRasterPaintDevice*>(device);
00789         d->rasterBuffer->prepare(dev);
00790 #endif
00791     } else {
00792         d->rasterBuffer->prepare(d->deviceRect.width(), d->deviceRect.height());
00793     }
00794 
00795     d->rasterBuffer->resetClip();
00796 
00797     d->matrix = QMatrix();
00798     d->txop = QPainterPrivate::TxNone;
00799 
00800     d->outlineMapper->setMatrix(d->matrix, d->txop);
00801     d->outlineMapper->m_clipper.setBoundingRect(d->deviceRect.adjusted(-10, -10, 10, 10));
00802 
00803     if (device->depth() == 1) {
00804         d->pen = QPen(Qt::color1);
00805         d->brush = QBrush(Qt::color0);
00806     } else {
00807         d->pen = QPen(Qt::black);
00808         d->brush = QBrush(Qt::NoBrush);
00809     }
00810 
00811     d->penData.init(d->rasterBuffer, this);
00812     d->penData.setup(d->pen.brush(), d->opacity);
00813     d->stroker = &d->basicStroker;
00814     d->basicStroker.setClipRect(d->deviceRect);
00815 
00816     d->brushData.init(d->rasterBuffer, this);
00817     d->brushData.setup(d->brush, d->opacity);
00818 
00819 #ifdef QT_EXPERIMENTAL_REGIONS
00820     updateClipRegion(QRegion(), Qt::NoClip);
00821 #else
00822     updateClipPath(QPainterPath(), Qt::NoClip);
00823 #endif
00824 
00825     setDirty(DirtyBrushOrigin);
00826 
00827     setActive(true);
00828     return true;
00829 }
00830 
00834 bool QRasterPaintEngine::end()
00835 {
00836     Q_D(QRasterPaintEngine);
00837 
00838     if (d->flushOnEnd)
00839         flush(d->pdev, QPoint());
00840 
00841     if (d->rasterBuffer->disabled_clip) {
00842         delete d->rasterBuffer->disabled_clip;
00843         d->rasterBuffer->disabled_clip = 0;
00844     }
00845 
00846     setActive(false);
00847 
00848 #ifdef Q_WS_QWS
00849     qResetDrawhelper();
00850 #endif
00851 
00852     return true;
00853 }
00854 
00858 void QRasterPaintEngine::releaseBuffer()
00859 {
00860     Q_D(QRasterPaintEngine);
00861     delete d->rasterBuffer;
00862     d->rasterBuffer = new QRasterBuffer;
00863 }
00864 
00868 QSize QRasterPaintEngine::size() const
00869 {
00870     Q_D(const QRasterPaintEngine);
00871     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
00872 }
00873 
00877 #ifndef QT_NO_DEBUG
00878 void QRasterPaintEngine::saveBuffer(const QString &s) const
00879 {
00880     Q_D(const QRasterPaintEngine);
00881     d->rasterBuffer->bufferImage().save(s, "PNG");
00882 }
00883 #endif
00884 
00888 void QRasterPaintEngine::setFlushOnEnd(bool flushOnEnd)
00889 {
00890     Q_D(QRasterPaintEngine);
00891 
00892     d->flushOnEnd = flushOnEnd;
00893 }
00894 
00895 
00901 void QRasterPaintEngine::flush(QPaintDevice *device, const QPoint &offset)
00902 {
00903     Q_D(QRasterPaintEngine);
00904     Q_ASSERT(device);
00905 
00906 #if defined(Q_WS_WIN)
00907     if (!d->rasterBuffer->hdc())
00908         return;
00909 
00910     if (device->devType() == QInternal::Widget) {
00911         HDC hdc = device->getDC();
00912 
00913         QRegion sysClip = systemClip();
00914         if (sysClip.isEmpty()) {
00915             BitBlt(hdc, d->deviceRect.x() + offset.x(), d->deviceRect.y() + offset.y(),
00916                    d->deviceRect.width(), d->deviceRect.height(),
00917                    d->rasterBuffer->hdc(), 0, 0, SRCCOPY);
00918         } else {
00919             QVector<QRect> rects = sysClip.rects();
00920             for (int i=0; i<rects.size(); ++i) {
00921                 QRect r = rects.at(i);
00922                 BitBlt(hdc,
00923                        r.x() + offset.x(), r.y() + offset.y(), r.width(), r.height(),
00924                        d->rasterBuffer->hdc(), r.x() - d->deviceRect.x(), r.y() - d->deviceRect.y(),
00925                        SRCCOPY);
00926             }
00927         }
00928 
00929         device->releaseDC(hdc);
00930     }
00931 #elif defined(Q_WS_MAC)
00932     extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
00933     extern void qt_mac_clip_cg(CGContextRef, const QRegion &, const QPoint *, CGAffineTransform *); //qpaintengine_mac.cpp
00934     if(CGContextRef ctx = qt_mac_cg_context(device)) {
00935         qt_mac_clip_cg(ctx, systemClip(), 0, 0);
00936         const CGRect source = CGRectMake(0, 0, d->deviceRect.width(), d->deviceRect.height());
00937         QCFType<CGImageRef> subimage;
00938 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
00939         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
00940             subimage = CGImageCreateWithImageInRect(d->rasterBuffer->m_data, source);
00941         } else
00942 #endif
00943         {
00944             int dw = d->deviceRect.width();
00945             int dh = d->deviceRect.height();
00946             QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(
00947                                                             d->rasterBuffer->buffer(),
00948                                                             d->rasterBuffer->buffer(),
00949                                                             dw*dh*sizeof(uint), 0);
00950             subimage = CGImageCreate(dw, dh, 8, 32, d->rasterBuffer->width() * sizeof(uint),
00951                                      QCFType<CGColorSpaceRef>(CGColorSpaceCreateDeviceRGB()),
00952                                      kCGImageAlphaPremultipliedFirst, provider, 0, 0,
00953                                      kCGRenderingIntentDefault);
00954         }
00955         const CGRect dest = CGRectMake(offset.x(), offset.y(),
00956                                        d->deviceRect.width(), d->deviceRect.height());
00957         HIViewDrawCGImage(ctx, &dest, subimage); //top left
00958         CGContextRelease(ctx);
00959         CGImageRelease(subimage);
00960     }
00961 #else
00962     Q_UNUSED(d);
00963     Q_UNUSED(device);
00964     Q_UNUSED(offset);
00965 #endif
00966 }
00967 
00971 void QRasterPaintEngine::updateMatrix(const QMatrix &matrix)
00972 {
00973     Q_D(QRasterPaintEngine);
00974 
00975     d->matrix = matrix;
00976     d->int_xform = false;
00977     if (d->matrix.m12() != 0 || d->matrix.m21() != 0) {
00978         d->txop = QPainterPrivate::TxRotShear;
00979     } else if (d->matrix.m11() != 1 || d->matrix.m22() != 1) {
00980         d->txop = QPainterPrivate::TxScale;
00981         d->int_xform = qreal(int(d->matrix.dx())) == d->matrix.dx()
00982                             && qreal(int(d->matrix.dy())) == d->matrix.dy()
00983                             && qreal(int(d->matrix.m11())) == d->matrix.m11()
00984                             && qreal(int(d->matrix.m22())) == d->matrix.m22();
00985     } else if (d->matrix.dx() != 0 || d->matrix.dy() != 0) {
00986         d->txop = QPainterPrivate::TxTranslate;
00987         d->int_xform = qreal(int(d->matrix.dx())) == d->matrix.dx()
00988                             && qreal(int(d->matrix.dy())) == d->matrix.dy();
00989     } else {
00990         d->txop = QPainterPrivate::TxNone;
00991         d->int_xform = true;
00992     }
00993 
00994     // 1/10000 == 0.0001, so we have good enough res to cover curves
00995     // that span the entire widget...
00996     d->inverseScale = qMax(1 / qMax( qMax(qAbs(matrix.m11()), qAbs(matrix.m22())),
00997                                      qMax(qAbs(matrix.m12()), qAbs(matrix.m21())) ),
00998                            qreal(0.0001));
00999 
01000     d->outlineMapper->setMatrix(d->matrix, d->txop);
01001     QMatrix penMatrix = (d->matrix.inverted()*d->pen.brush().matrix().inverted()).inverted();
01002     d->penData.setupMatrix(penMatrix,
01003                            d->txop, d->bilinear);
01004     QMatrix brushMatrix = (d->brushMatrix().inverted() * d->brush.matrix().inverted()).inverted();
01005     d->brushData.setupMatrix(brushMatrix, d->txop, d->bilinear);
01006 }
01007 
01011 void QRasterPaintEngine::updateState(const QPaintEngineState &state)
01012 {
01013     Q_D(QRasterPaintEngine);
01014 
01015     QPaintEngine::DirtyFlags flags = state.state();
01016 
01017     bool update_fast_pen = false;
01018 
01019     if (flags & DirtyTransform) {
01020         update_fast_pen = true;
01021         updateMatrix(state.matrix());
01022     }
01023 
01024     if (flags & DirtyOpacity) {
01025         update_fast_pen = true;
01026         d->opacity = qRound(state.opacity() * 256.0);
01027         if (d->opacity > 256)
01028             d->opacity = 256;
01029         if (d->opacity < 0)
01030             d->opacity = 0;
01031 
01032         // Force update pen/brush as to get proper alpha colors propagated
01033         flags |= DirtyPen;
01034         flags |= DirtyBrush;
01035     }
01036 
01037     if (flags & DirtyPen) {
01038         update_fast_pen = true;
01039         d->pen = state.pen();
01040 
01041         if (d->pen.style() == Qt::CustomDashLine && d->pen.dashPattern().size() == 0)
01042             d->pen.setStyle(Qt::SolidLine);
01043 
01044         d->basicStroker.setJoinStyle(d->pen.joinStyle());
01045         d->basicStroker.setCapStyle(d->pen.capStyle());
01046         d->basicStroker.setMiterLimit(d->pen.miterLimit());
01047 
01048         qreal penWidth = d->pen.widthF();
01049         if (penWidth == 0)
01050             d->basicStroker.setStrokeWidth(1);
01051         else
01052             d->basicStroker.setStrokeWidth(penWidth);
01053 
01054         Qt::PenStyle pen_style = d->pen.style();
01055         if(pen_style == Qt::SolidLine) {
01056             d->stroker = &d->basicStroker;
01057         } else if (pen_style != Qt::NoPen) {
01058             if (!d->dashStroker)
01059                 d->dashStroker = new QDashStroker(&d->basicStroker);
01060             if (penWidth == 0) {
01061                 d->dashStroker->setClipRect(d->deviceRect);
01062             } else {
01063                 QRectF clipRect = d->matrix.inverted().mapRect(QRectF(d->deviceRect));
01064                 d->dashStroker->setClipRect(clipRect);
01065             }
01066             d->dashStroker->setDashPattern(d->pen.dashPattern());
01067             d->stroker = d->dashStroker;
01068         } else {
01069             d->stroker = 0;
01070         }
01071         d->penData.setup(pen_style == Qt::NoPen ? QBrush() : d->pen.brush(), d->opacity);
01072     }
01073 
01074     if (flags & (DirtyBrush|DirtyBrushOrigin)) {
01075         QBrush brush = state.brush();
01076         d->brush = brush;
01077         d->brushOffset = state.brushOrigin();
01078         d->brushData.setup(d->brush, d->opacity);
01079         d->brushData.setupMatrix((d->brushMatrix().inverted() * d->brush.matrix().inverted()).inverted(),
01080                                  d->txop, d->bilinear);
01081     }
01082 
01083     if (flags & (DirtyClipPath | DirtyClipRegion)) {
01084         d->user_clip_enabled = true;
01085         // If we're setting a clip, we kill the old clip
01086         if (d->rasterBuffer->disabled_clip) {
01087             delete d->rasterBuffer->disabled_clip;
01088             d->rasterBuffer->disabled_clip = 0;
01089         }
01090     }
01091 
01092     if (flags & DirtyClipPath) {
01093 #ifdef QT_EXPERIMENTAL_REGIONS
01094         QPolygon polygon = state.clipPath().toFillPolygon().toPolygon();
01095         updateClipRegion(QRegion(polygon, state.clipPath().fillRule()),
01096                          state.clipOperation());
01097 #else
01098         updateClipPath(state.clipPath(), state.clipOperation());
01099 
01100 #endif
01101     } else if (flags & DirtyClipRegion) {
01102         updateClipRegion(state.clipRegion(), state.clipOperation());
01103 
01104     } else if (flags & DirtyClipEnabled) {
01105 
01106         if (state.isClipEnabled() != d->user_clip_enabled) {
01107             d->user_clip_enabled = state.isClipEnabled();
01108 
01109             // The tricky case... When we disable clipping we still do
01110             // system clip so we need to rasterize the system clip and
01111             // replace the current clip with it. Since people might
01112             // choose to set clipping to true later on we have to the
01113             // current one (in disabled_clip).
01114             if (!d->baseClip.isEmpty()) {
01115                 if (!state.isClipEnabled()) { // save current clip for later
01116                     Q_ASSERT(!d->rasterBuffer->disabled_clip);
01117                     d->rasterBuffer->disabled_clip = d->rasterBuffer->clip;
01118                     d->rasterBuffer->clip = 0;
01119 #ifdef QT_EXPERIMENTAL_REGIONS
01120                     updateClipRegion(QRegion(), Qt::NoClip);
01121 #else
01122                     updateClipPath(QPainterPath(), Qt::NoClip);
01123 #endif
01124                 } else { // re-enable old clip
01125                     Q_ASSERT(d->rasterBuffer->disabled_clip);
01126                     d->rasterBuffer->resetClip();
01127                     d->rasterBuffer->clip = d->rasterBuffer->disabled_clip;
01128                     d->rasterBuffer->disabled_clip = 0;
01129                 }
01130             } else {
01131                 if (!state.isClipEnabled()) {
01132 #ifdef QT_EXPERIMENTAL_REGIONS
01133                     updateClipRegion(QRegion(), Qt::NoClip);
01134 #else
01135                     updateClipPath(QPainterPath(), Qt::NoClip);
01136 #endif
01137                 } else {
01138 #ifdef QT_EXPERIMENTAL_REGIONS
01139                     updateClipRegion(state.clipRegion(), state.clipOperation());
01140 #else
01141                     updateClipPath(state.clipPath(), state.clipOperation());
01142 #endif
01143                 }
01144             }
01145             d->penData.adjustSpanMethods();
01146             d->brushData.adjustSpanMethods();
01147         }
01148     }
01149 
01150     if (!d->mono_surface) {
01151         if (flags & DirtyHints) {
01152             update_fast_pen = true;
01153             d->antialiased = bool(state.renderHints() & QPainter::Antialiasing);
01154             d->bilinear = bool(state.renderHints() & QPainter::SmoothPixmapTransform);
01155             // propegate state to data's
01156             d->brushData.bilinear = d->penData.bilinear = d->bilinear;
01157             d->penData.adjustSpanMethods();
01158             d->brushData.adjustSpanMethods();
01159 
01160         }
01161 
01162         if (flags & DirtyCompositionMode) {
01163             d->rasterBuffer->compositionMode = state.compositionMode();
01164         }
01165     }
01166 
01167     if (update_fast_pen) {
01168         d->fast_pen = !d->antialiased
01169                       && (d->pen.widthF() == 0
01170                           || d->pen.widthF() <= 1 && d->txop <= QPainterPrivate::TxTranslate);
01171     }
01172 }
01173 
01177 void QRasterPaintEngine::updateClipRegion(const QRegion &r, Qt::ClipOperation op)
01178 {
01179 #ifdef QT_DEBUG_DRAW
01180     qDebug() << " - QRasterPaintEngine::updateClipRegion() op=" << op << r;
01181 #endif
01182 
01183 #ifdef QT_EXPERIMENTAL_REGIONS
01184     Q_D(QRasterPaintEngine);
01185 
01186     switch (op) {
01187     case Qt::NoClip:
01188         d->clipRegion = d->deviceRect;
01189         break;
01190     case Qt::IntersectClip:
01191         d->clipRegion &= d->matrix.map(r);
01192         break;
01193     case Qt::ReplaceClip:
01194         if (r.isEmpty())
01195             d->clipRegion = d->deviceRect;
01196         else
01197             d->clipRegion = d->matrix.map(r);
01198         break;
01199     case Qt::UniteClip:
01200         d->clipRegion |= d->matrix.map(r);
01201         break;
01202     default:
01203         break;
01204     }
01205 
01206     const QRegion sysClip = systemClip();
01207     if (!sysClip.isEmpty())
01208         d->clipRegion &= sysClip;
01209 
01210     if (!d->clipRegion.isEmpty() && d->clipRegion.rects().count() == 1) {
01211         d->setSimpleClip(d->clipRegion.boundingRect());
01212         return;
01213     }
01214 #endif // QT_EXPERIMENTAL_REGIONS
01215 
01216     QPainterPath p;
01217     p.addRegion(r);
01218     updateClipPath(p, op);
01219 }
01220 
01221 #ifdef QT_EXPERIMENTAL_REGIONS
01222 void QRasterPaintEnginePrivate::setSimpleClip(const QRect &rect)
01223 {
01224     if (!rasterBuffer->clip)
01225         rasterBuffer->clip = new QClipData(rasterBuffer->height());
01226     rasterBuffer->clip->setSimpleClip(rect);
01227     rasterBuffer->clipEnabled = true;
01228 
01229     penData.adjustSpanMethods();
01230     brushData.adjustSpanMethods();
01231 }
01232 #endif // QT_EXPERIMENTAL_REGIONS
01233 
01237 void QRasterPaintEngine::updateClipPath(const QPainterPath &path, Qt::ClipOperation op)
01238 {
01239     Q_D(QRasterPaintEngine);
01240 #ifdef QT_DEBUG_DRAW
01241     qDebug() << " - QRasterPaintEngine::updateClipPath(), op="
01242              << op
01243              << path.boundingRect();
01244 #endif
01245     d->updateClip_helper(path, op);
01246 
01247     // Reset the baseClip if the operation requires it.
01248     if (!d->baseClip.isEmpty()) {
01249         switch (op) {
01250         case Qt::UniteClip:
01251         case Qt::ReplaceClip:
01252         case Qt::NoClip:
01253             d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
01254             d->updateClip_helper(d->baseClip, Qt::IntersectClip);
01255             d->outlineMapper->setMatrix(d->matrix, d->txop);
01256             break;
01257         default:
01258             break;
01259         }
01260     }
01261 }
01262 
01266 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
01267 {
01268 #ifdef QT_DEBUG_DRAW
01269     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
01270 #endif
01271 
01272     if (!fillData->blend)
01273         return;
01274 
01275     Q_D(QRasterPaintEngine);
01276     d->rasterize(d->outlineMapper->convertPath(path), fillData->blend, fillData, d->rasterBuffer);
01277 }
01278 
01279 #ifdef QT_EXPERIMENTAL_REGIONS
01280 static void fillRect(const QRect &r, const QRegion &clipRegion, QSpanData *data)
01281 #else
01282 static void fillRect(const QRect &r, QSpanData *data)
01283 #endif
01284 {
01285     QRect rect = r.normalized();
01286     int x1 = qMax(rect.x(), 0);
01287     int x2 = qMin(rect.width() + rect.x(), data->rasterBuffer->width());
01288     int y1 = qMax(rect.y(), 0);
01289     int y2 = qMin(rect.height() + rect.y(), data->rasterBuffer->height());
01290     QClipData *clip = data->rasterBuffer->clipEnabled ? data->rasterBuffer->clip : 0;
01291     if (clip) {
01292         x1 = qMax(x1, clip->xmin);
01293         x2 = qMin(x2, clip->xmax);
01294         y1 = qMax(y1, clip->ymin);
01295         y2 = qMin(y2, clip->ymax);
01296     }
01297 
01298 #ifdef QT_EXPERIMENTAL_REGIONS
01299     ProcessSpans blend = qt_region_strictContains(clipRegion, rect) ?
01300                          data->unclipped_blend : data->blend;
01301 #endif
01302 
01303     int len = x2 - x1;
01304 
01305     if (len > 0) {
01306         const int nspans = 256;
01307         QT_FT_Span spans[nspans];
01308 
01309         Q_ASSERT(data->blend);
01310         int y = y1;
01311         while (y < y2) {
01312             int n = qMin(nspans, y2 - y);
01313             int i = 0;
01314             while (i < n) {
01315                 spans[i].x = x1;
01316                 spans[i].len = len;
01317                 spans[i].y = y + i;
01318                 spans[i].coverage = 255;
01319                 ++i;
01320             }
01321 
01322 #ifdef QT_EXPERIMENTAL_REGIONS
01323             blend(n, spans, data);
01324 #else
01325             data->blend(n, spans, data);
01326 #endif
01327             y += n;
01328         }
01329     }
01330 }
01331 
01335 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
01336 {
01337 #ifdef QT_DEBUG_DRAW
01338     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
01339 #endif
01340     Q_D(QRasterPaintEngine);
01341     if (!d->antialiased && d->txop <= QPainterPrivate::TxTranslate) {
01342         int offset_x = int(d->matrix.dx());
01343         int offset_y = int(d->matrix.dy());
01344 
01345         const QRect *lastRect = rects + rectCount;
01346 
01347         while (rects < lastRect) {
01348 
01349             QRect rect = rects->normalized();
01350             if (d->brushData.blend) {
01351                 QRect r = rect.translated(offset_x, offset_y);
01352 #ifdef QT_EXPERIMENTAL_REGIONS
01353                 fillRect(r, d->clipRegion, &d->brushData);
01354 #else
01355                 fillRect(r, &d->brushData);
01356 #endif
01357             }
01358 
01359             if (d->penData.blend) {
01360                 ProcessSpans brush_blend = d->brushData.blend;
01361                 d->brushData.blend = 0;
01362                 int left = rect.x();
01363                 int right = rect.x() + rect.width();
01364                 int top = rect.y();
01365                 int bottom = rect.y() + rect.height();
01366                 QPoint pts[] = { QPoint(left, top),
01367                                  QPoint(right, top),
01368                                  QPoint(right, bottom),
01369                                  QPoint(left, bottom) };
01370                 QRasterPaintEngine::drawPolygon(pts, 4, WindingMode);
01371                 d->brushData.blend = brush_blend;
01372             }
01373 
01374             ++rects;
01375         }
01376     } else {
01377         QPaintEngine::drawRects(rects, rectCount);
01378     }
01379 }
01380 
01384 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
01385 {
01386 #ifdef QT_DEBUG_DRAW
01387     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
01388 #endif
01389     for (int i=0; i<rectCount; ++i) {
01390         const QRectF &rf = rects[i];
01391         QPointF pts[4] = { QPointF(rf.x(), rf.y()),
01392                            QPointF(rf.x() + rf.width(), rf.y()),
01393                            QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
01394                            QPointF(rf.x(), rf.y() + rf.height()) };
01395         drawPolygon(pts, 4, ConvexMode);
01396     }
01397 }
01398 
01402 void QRasterPaintEngine::drawPath(const QPainterPath &path)
01403 {
01404 #ifdef QT_DEBUG_DRAW
01405     QRectF bounds = path.boundingRect();
01406     qDebug(" - QRasterPaintEngine::drawPath(), [%.2f, %.2f, %.2f, %.2f]",
01407            bounds.x(), bounds.y(), bounds.width(), bounds.height());
01408 #endif
01409     if (path.isEmpty())
01410         return;
01411 
01412     Q_D(QRasterPaintEngine);
01413 
01414     if (d->brushData.blend) {
01415         d->outlineMapper->setMatrix(d->matrix, d->txop);
01416         fillPath(path, &d->brushData);
01417     }
01418 
01419     if (!d->penData.blend)
01420         return;
01421 
01422     {
01423         Q_ASSERT(d->stroker);
01424         qreal width = d->pen.widthF();
01425         d->outlineMapper->beginOutline(Qt::WindingFill);
01426         if (width == 0) {
01427             d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
01428             d->stroker->strokePath(path, d->outlineMapper, d->matrix);
01429         } else {
01430             d->outlineMapper->setMatrix(d->matrix, d->txop);
01431             d->stroker->strokePath(path, d->outlineMapper, QMatrix());
01432         }
01433         d->outlineMapper->endOutline();
01434 
01435         d->rasterize(d->outlineMapper->outline(), d->penData.blend, &d->penData, d->rasterBuffer);
01436         d->outlineMapper->setMatrix(d->matrix, d->txop);
01437     }
01438 
01439 }
01440 
01444 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
01445 {
01446     Q_D(QRasterPaintEngine);
01447 #ifdef QT_DEBUG_DRAW
01448     qDebug(" - QRasterPaintEngine::drawPolygon(), pointCount=%d", pointCount);
01449     for (int i=0; i<pointCount; ++i)
01450         qDebug() << "   - " << points[i];
01451 #endif
01452     Q_ASSERT(pointCount >= 2);
01453 
01454     // Do the fill
01455     if (d->brushData.blend && mode != PolylineMode) {
01456 
01457         // Compose polygon fill..,
01458         d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
01459         d->outlineMapper->moveTo(*points);
01460         const QPointF *p = points;
01461         const QPointF *ep = points + pointCount - 1;
01462         do {
01463             d->outlineMapper->lineTo(*(++p));
01464         } while (p < ep);
01465         d->outlineMapper->endOutline();
01466 
01467         // scanconvert.
01468         d->rasterize(d->outlineMapper->outline(), d->brushData.blend, &d->brushData, d->rasterBuffer);
01469     }
01470 
01471     // Do the outline...
01472     if (d->penData.blend) {
01473 
01474         bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
01475 
01476         if (d->fast_pen && d->pen.brush().isOpaque()) {
01477             // Use fast path for 0 width /  trivial pens.
01478 
01479             QRect devRect(0, 0, d->deviceRect.width(), d->deviceRect.height());
01480 
01481             LineDrawMode mode_for_last = (d->pen.capStyle() != Qt::FlatCap
01482                                           ? LineDrawIncludeLastPixel
01483                                           : LineDrawNormal);
01484             int dashOffset = 0;
01485 
01486             // Draw all the line segments.
01487             for (int i=1; i<pointCount; ++i) {
01488                 QPointF lp1 = points[i-1] * d->matrix;
01489                 QPointF lp2 = points[i] * d->matrix;
01490                 if (d->pen.style() == Qt::SolidLine) {
01491                     drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
01492                                         qFloor(lp2.x()), qFloor(lp2.y()),
01493                                         d->penData.blend, &d->penData,
01494                                         i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
01495                                         devRect);
01496                 } else {
01497                     drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
01498                                                qFloor(lp2.x()), qFloor(lp2.y()),
01499                                                &d->pen,
01500                                                d->penData.blend, &d->penData,
01501                                                i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
01502                                                devRect, &dashOffset);
01503                 }
01504             }
01505 
01506             // Polygons are implicitly closed.
01507             if (needs_closing) {
01508                 QPointF lp1 = points[pointCount-1] * d->matrix;
01509                 QPointF lp2 = points[0] * d->matrix;
01510                 if (d->pen.style() == Qt::SolidLine) {
01511                     drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
01512                                         qFloor(lp2.x()), qFloor(lp2.y()),
01513                                         d->penData.blend, &d->penData,
01514                                         LineDrawIncludeLastPixel,
01515                                         devRect);
01516                 } else {
01517                     drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
01518                                                qFloor(lp2.x()), qFloor(lp2.y()),
01519                                                &d->pen,
01520                                                d->penData.blend, &d->penData,
01521                                                LineDrawIncludeLastPixel,
01522                                                devRect, &dashOffset);
01523                 }
01524             }
01525 
01526         } else {
01527             // fallback case for complex or transformed pens.
01528             qreal width = d->pen.widthF();
01529             d->outlineMapper->beginOutline(Qt::WindingFill);
01530             if (width == 0) {
01531                 d->basicStroker.setStrokeWidth(1);
01532                 d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
01533                 d->stroker->strokePolygon(points, pointCount, needs_closing,
01534                                           d->outlineMapper, d->matrix);
01535             } else {
01536                 d->basicStroker.setStrokeWidth(width);
01537                 d->outlineMapper->setMatrix(d->matrix, d->txop);
01538                 d->stroker->strokePolygon(points, pointCount, needs_closing,
01539                                           d->outlineMapper, QMatrix());
01540             }
01541             d->outlineMapper->endOutline();
01542 
01543             d->rasterize(d->outlineMapper->outline(), d->penData.blend, &d->penData, d->rasterBuffer);
01544 
01545             d->outlineMapper->setMatrix(d->matrix, d->txop);
01546         }
01547     }
01548 
01549 }
01550 
01554 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
01555 {
01556     Q_D(QRasterPaintEngine);
01557     if (!(d->int_xform && d->fast_pen)) {
01558         // this calls the float version
01559         QPaintEngine::drawPolygon(points, pointCount, mode);
01560         return;
01561     }
01562 
01563 #ifdef QT_DEBUG_DRAW
01564     qDebug(" - QRasterPaintEngine::drawPolygon(), pointCount=%d", pointCount);
01565     for (int i=0; i<pointCount; ++i)
01566         qDebug() << "   - " << points[i];
01567 #endif
01568     Q_ASSERT(pointCount >= 2);
01569 
01570     // Do the fill
01571     if (d->brushData.blend && mode != PolylineMode) {
01572 
01573         // Compose polygon fill..,
01574         d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
01575         d->outlineMapper->moveTo(*points);
01576         const QPoint *p = points;
01577         const QPoint *ep = points + pointCount - 1;
01578         do {
01579             d->outlineMapper->lineTo(*(++p));
01580         } while (p < ep);
01581         d->outlineMapper->endOutline();
01582 
01583         // scanconvert.
01584         d->rasterize(d->outlineMapper->outline(), d->brushData.blend, &d->brushData, d->rasterBuffer);
01585     }
01586 
01587     // Do the outline...
01588     if (d->penData.blend) {
01589 
01590         bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
01591 
01592         QRect devRect(0, 0, d->deviceRect.width(), d->deviceRect.height());
01593 
01594         LineDrawMode mode_for_last = (d->pen.capStyle() != Qt::FlatCap
01595                                       ? LineDrawIncludeLastPixel
01596                                       : LineDrawNormal);
01597 
01598         int m11 = int(d->matrix.m11());
01599         int m22 = int(d->matrix.m22());
01600         int dx = int(d->matrix.dx());
01601         int dy = int(d->matrix.dy());
01602 
01603         int dashOffset = 0;
01604 
01605         // Draw all the line segments.
01606         for (int i=1; i<pointCount; ++i) {
01607             if (d->pen.style() == Qt::SolidLine)
01608                 drawLine_midpoint_i(points[i-1].x() * m11 + dx, points[i-1].y() * m22 + dy,
01609                                     points[i].x() * m11 + dx, points[i].y() * m22 + dy,
01610                                     d->penData.blend, &d->penData,
01611                                     i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
01612                                     devRect);
01613             else
01614                 drawLine_midpoint_dashed_i(points[i-1].x() * m11 + dx, points[i-1].y() * m22 + dy,
01615                                            points[i].x() * m11 + dx, points[i].y() * m22 + dy,
01616                                            &d->pen,
01617                                            d->penData.blend, &d->penData,
01618                                            i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
01619                                            devRect, &dashOffset);
01620 
01621         }
01622 
01623         // Polygons are implicitly closed.
01624         if (needs_closing) {
01625             if (d->pen.style() == Qt::SolidLine)
01626                 drawLine_midpoint_i(points[pointCount-1].x() * m11 + dx, points[pointCount-1].y() * m22 + dy,
01627                                     points[0].x() * m11 + dx, points[0].y() * m22 + dy,
01628                                     d->penData.blend, &d->penData, LineDrawIncludeLastPixel,
01629                                     devRect);
01630             else
01631                 drawLine_midpoint_dashed_i(points[pointCount-1].x() * m11 + dx, points[pointCount-1].y() * m22 + dy,
01632                                     points[0].x() * m11 + dx, points[0].y() * m22 + dy,
01633                                            &d->pen,
01634                                            d->penData.blend, &d->penData, LineDrawIncludeLastPixel,
01635                                            devRect, &dashOffset);
01636         }
01637 
01638     }
01639 
01640 }
01641 
01645 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
01646 {
01647 #ifdef QT_DEBUG_DRAW
01648     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
01649 #endif
01650 
01651     Q_D(QRasterPaintEngine);
01652 
01653     if (pixmap.depth() == 1) {
01654         if (d->txop <= QPainterPrivate::TxTranslate
01655             && r.size() == sr.size()
01656             && r.size() == pixmap.size()) {
01657             d->drawBitmap(r.topLeft() + QPointF(d->matrix.dx(), d->matrix.dy()), pixmap, &d->penData);
01658             return;
01659         } else {
01660             drawImage(r, d->rasterBuffer->colorizeBitmap(pixmap.toImage(), d->pen.color()), sr);
01661         }
01662     } else {
01663 #if defined(Q_WS_MAC)
01664         if(CGContextRef ctx = macCGContext()) {
01665             const CGRect dest = CGRectMake(r.x(), r.y(), r.width(), r.height());
01666             QCFType<CGImageRef> subimage;
01667 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
01668             if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
01669                 const CGRect source = CGRectMake(sr.x(), sr.y(), sr.width(), sr.height());
01670                 subimage = CGImageCreateWithImageInRect(pixmap.data->cg_data, source);
01671             } else
01672 #endif
01673             {
01674                 int sx = qRound(sr.x());
01675                 int sy = qRound(sr.y());
01676                 int sw = qRound(sr.width());
01677                 int sh = qRound(sr.height());
01678                 quint32 *pantherData = pixmap.data->pixels + (sy * pixmap.width() + sx);
01679                 QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(0,
01680                                                                    pantherData, sw*sh*sizeof(uint),
01681                                                                    0);
01682                 subimage = CGImageCreate(sw, sh, 8, 32, pixmap.width() * sizeof(uint),
01683                                 QCFType<CGColorSpaceRef>(CGColorSpaceCreateDeviceRGB()),
01684                                 kCGImageAlphaPremultipliedFirst, provider, 0, 0,
01685                                 kCGRenderingIntentDefault);
01686             }
01687             HIViewDrawCGImage(ctx, &dest, subimage); //top left
01688         } else
01689 #endif
01690             drawImage(r, pixmap.toImage(), sr);
01691     }
01692 
01693 }
01694 
01698 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
01699                                    Qt::ImageConversionFlags)
01700 {
01701 #ifdef QT_DEBUG_DRAW
01702     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
01703 #endif
01704 
01705     Q_D(QRasterPaintEngine);
01706     QSpanData textureData;
01707     textureData.init(d->rasterBuffer, this);
01708     textureData.type = QSpanData::Texture;
01709     textureData.initTexture(&img, d->opacity);
01710 
01711     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
01712 
01713     if (d->txop > QPainterPrivate::TxTranslate || stretch_sr) {
01714         QMatrix copy = d->matrix;
01715         copy.translate(r.x(), r.y());
01716         if (stretch_sr)
01717             copy.scale(r.width() / sr.width(), r.height() / sr.height());
01718         copy.translate(-sr.x(), -sr.y());
01719         textureData.setupMatrix(copy, QPainterPrivate::TxRotShear, d->bilinear);
01720   textureData.adjustSpanMethods();
01721 
01722         bool wasAntialiased = d->antialiased;
01723         if (!d->antialiased)
01724             d->antialiased = d->bilinear;
01725         QPainterPath path;
01726         path.addRect(r);
01727         fillPath(path, &textureData);
01728         d->antialiased = wasAntialiased;
01729     } else {
01730         textureData.dx = -(r.x() + d->matrix.dx()) + sr.x();
01731         textureData.dy = -(r.y() + d->matrix.dy()) + sr.y();
01732 
01733         QRectF rr = r;
01734         rr.translate(d->matrix.dx(), d->matrix.dy());
01735 #ifdef QT_EXPERIMENTAL_REGIONS
01736         fillRect(rr.toRect(), d->clipRegion, &textureData);
01737 #else
01738         fillRect(rr.toRect(), &textureData);
01739 #endif
01740     }
01741 }
01742 
01746 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
01747 {
01748 #ifdef QT_DEBUG_DRAW
01749     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
01750 #endif
01751     Q_D(QRasterPaintEngine);
01752 
01753     QImage image;
01754     if (pixmap.depth() == 1)
01755         image = d->rasterBuffer->colorizeBitmap(pixmap.toImage(), d->pen.color());
01756     else
01757         image = pixmap.toImage();
01758 
01759     QSpanData textureData;
01760     textureData.init(d->rasterBuffer, this);
01761     textureData.type = QSpanData::Texture;
01762     textureData.initTexture(&image, d->opacity, TextureData::Tiled);
01763 
01764     if (d->txop > QPainterPrivate::TxTranslate) {
01765         QMatrix copy = d->matrix;
01766         copy.translate(r.x(), r.y());
01767         copy.translate(-sr.x(), -sr.y());
01768         textureData.setupMatrix(copy, QPainterPrivate::TxRotShear, d->bilinear);
01769 
01770         bool wasAntialiased = d->antialiased;
01771         if (!d->antialiased)
01772             d->antialiased = d->bilinear;
01773         QPainterPath path;
01774         path.addRect(r);
01775         fillPath(path, &textureData);
01776         d->antialiased = wasAntialiased;
01777     } else {
01778         textureData.dx = -(r.x() + d->matrix.dx()) + sr.x();
01779         textureData.dy = -(r.y() + d->matrix.dy()) + sr.y();
01780 
01781         QRectF rr = r;
01782         rr.translate(d->matrix.dx(), d->matrix.dy());
01783 #ifdef QT_EXPERIMENTAL_REGIONS
01784         fillRect(rr.toRect(), d->clipRegion, &textureData);
01785 #else
01786         fillRect(rr.toRect(), &textureData);
01787 #endif
01788     }
01789 
01790 }
01791 
01792 
01793 #ifdef Q_WS_QWS
01794 //QWS hack
01795 static inline bool monoVal(const uchar* s, int x)
01796 {
01797     return  (s[x>>3] << (x&7)) & 0x80;
01798 }
01799 
01803 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, bool mono, int rx,int ry,int w,int h)
01804 {
01805     Q_D(QRasterPaintEngine);
01806 
01807     if (!d->penData.blend)
01808         return;
01809 
01810     int y0 = (ry < 0) ? -ry : 0;
01811     int x0 = (rx < 0) ? -rx : 0;
01812 
01813     QRasterBuffer *rb = d->rasterBuffer;
01814 
01815     w = qMin(w, rb->width() - rx);
01816     h = qMin(h, rb->height() - ry);
01817 
01818 #ifdef QT_EXPERIMENTAL_REGIONS
01819     if (w <= 0 || h <= 0)
01820         return;
01821 
01822     const QRect rect(rx, ry, w, h);
01823     const QClipData *clip = d->rasterBuffer->clip;
01824     if (clip) {
01825         const QRect bound = QRect(clip->xmin, clip->ymin,
01826                                   clip->xmax - clip->xmin,
01827                                   clip->ymax - clip->ymin);
01828         if ((bound & rect).isEmpty())
01829             return;
01830     }
01831 
01832     const bool unclipped = qt_region_strictContains(d->clipRegion, rect);
01833     ProcessSpans blend = unclipped ? d->penData.unclipped_blend : d->penData.blend;
01834 #endif
01835 
01836     const int NSPANS = 256;
01837     QSpan spans[NSPANS];
01838     int current = 0;
01839 
01840     const uchar * scanline = static_cast<const uchar *>(src) + y0*bpl;
01841     if (mono) {
01842         for (int y=y0; y < h; ++y) {
01843             for (int x = x0; x < w; ) {
01844                 if (!monoVal(scanline, x)) {
01845                     ++x;
01846                     continue;
01847                 }
01848 
01849                 if (current == NSPANS) {
01850 #ifdef QT_EXPERIMENTAL_REGIONS
01851                     blend(current, spans, &d->penData);
01852 #else
01853                     d->penData.blend(current, spans, &d->penData);
01854 #endif
01855                     current = 0;
01856                 }
01857                 spans[current].x = x + rx;
01858                 spans[current].y = y + ry;
01859                 spans[current].coverage = 255;
01860                 int len = 1;
01861                 ++x;
01862                 // extend span until we find a different one.
01863                 while (x < w && monoVal(scanline, x)) {
01864                     ++x;
01865                     ++len;
01866                 }
01867                 spans[current].len = len;
01868                 ++current;
01869             }
01870             scanline += bpl;
01871         }
01872     } else {
01873         for (int y=y0; y < h; ++y) {
01874             for (int x = x0; x < w; ) {
01875                 // Skip those with 0 coverage
01876                 if (scanline[x] == 0) {
01877                     ++x;
01878                     continue;
01879                 }
01880 
01881                 if (current == NSPANS) {
01882 #ifdef QT_EXPERIMENTAL_REGIONS
01883                     blend(current, spans, &d->penData);
01884 #else
01885                     d->penData.blend(current, spans, &d->penData);
01886 #endif
01887                     current = 0;
01888                 }
01889                 int coverage = scanline[x];
01890                 spans[current].x = x + rx;
01891                 spans[current].y = y + ry;
01892                 spans[current].coverage = coverage;
01893                 int len = 1;
01894                 ++x;
01895 
01896                 // extend span until we find a different one.
01897                 while (x < w && scanline[x] == coverage) {
01898                     ++x;
01899                     ++len;
01900                 }
01901                 spans[current].len = len;
01902                 ++current;
01903             }
01904             scanline += bpl;
01905         }
01906     }
01907 //     qDebug() << "alphaPenBlt: num spans=" << current
01908 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
01909         // Call span func for current set of spans.
01910     if (current != 0)
01911 #ifdef QT_EXPERIMENTAL_REGIONS
01912         blend(current, spans, &d->penData);
01913 #else
01914         d->penData.blend(current, spans, &d->penData);
01915 #endif
01916 }
01917 
01923 void QRasterPaintEngine::qwsFillRect(int x, int y, int w, int h)
01924 {
01925     Q_D(QRasterPaintEngine);
01926     int x1 = qMax(x,0);
01927     int x2 = qMin(x+w, d->rasterBuffer->width());
01928     int y1 = qMax(y, 0);
01929     int y2 = qMin(y+h, d->rasterBuffer->height());;
01930 
01931     int len = x2 - x1;
01932 
01933     if (d->penData.blend && len > 0) {
01934         QT_FT_Span span;
01935         span.x = x1;
01936         span.len = x2 - x1;
01937         span.y = y;
01938         span.coverage = 255;
01939 
01940         // draw the fill
01941         for (int y=y1; y<y2; ++y) {
01942             d->penData.blend(1, &span, &d->penData);
01943         }
01944     }
01945 }
01946 #endif
01947 
01951 #ifdef Q_WS_X11
01952 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
01953 {
01954     QPaintEngine::drawTextItem(p, textItem);
01955     // #####
01956 }
01957 
01958 #else
01959 
01960 #if defined(Q_WS_WIN)
01961 bool QRasterPaintEngine::drawTextInFontBuffer(const QRect &devRect, int xmin, int ymin, int xmax,
01962                                               int ymax, const QTextItem &textItem, bool clearType,
01963                                               qreal leftBearingReserve, const QPointF &topLeft)
01964 {
01965     Q_D(QRasterPaintEngine);
01966     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
01967 
01968     if (d->mono_surface) {
01969         // Some extra work to get proper rasterization of text on monochrome targets
01970         HBITMAP bitmap = CreateBitmap(devRect.width(), devRect.height(), 1, 1, 0);
01971         HDC hdc = CreateCompatibleDC(qt_win_display_dc());
01972         HGDIOBJ null_bitmap = SelectObject(hdc, bitmap);
01973         SelectObject(hdc, GetStockObject(WHITE_BRUSH));
01974         SelectObject(hdc, GetStockObject(NULL_PEN));
01975         Rectangle(hdc, 0, 0, devRect.width() + 1, devRect.height() + 1);
01976 
01977         // Fill buffer with stuff
01978         SelectObject(hdc, GetStockObject(BLACK_BRUSH));
01979         SelectObject(hdc, GetStockObject(BLACK_PEN));
01980         SetTextColor(hdc, RGB(0,0,0));
01981         qt_draw_text_item(QPointF(leftBearingReserve, ti.ascent.toReal()), ti, hdc,
01982             false, QMatrix(d->matrix.m11(), d->matrix.m12(), d->matrix.m21(),
01983             d->matrix.m22(), 0, 0), topLeft);
01984 
01985         BitBlt(d->fontRasterBuffer->hdc(), 0, 0, devRect.width(), devRect.height(),
01986                hdc, 0, 0, SRCCOPY);
01987         SelectObject(hdc, null_bitmap);
01988         DeleteObject(bitmap);
01989         DeleteDC(hdc);
01990 
01991         return false;
01992     } else {
01993         // Let Windows handle the composition of background and foreground for cleartype text
01994         QRgb penColor = 0;
01995         bool brokenRasterBufferAlpha = false;
01996         if (clearType) {
01997             penColor = d->penData.solid.color;
01998 
01999             // Copy background from raster buffer
02000             for (int y=ymin; y<ymax; ++y) {
02001                 QRgb *sourceScanline = (QRgb *) d->rasterBuffer->scanLine(y);
02002                 QRgb *destScanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y());
02003                 for (int x=xmin; x<xmax; ++x) {
02004                     uint color = sourceScanline[x];
02005 
02006                     // If the alpha channel of the raster buffer has previously been
02007                     // broken by GDI, we assume there are valid colors there and
02008                     // use clear type anyway (this is for XP style)
02009                     int alpha = qAlpha(color);
02010                     if (qRed(color) > alpha || qGreen(color) > alpha || qBlue(color) > alpha)
02011                         brokenRasterBufferAlpha = true;
02012 
02013                     // If the background is transparent, set it to completely opaque so we will
02014                     // recognize it after Windows screws up the alpha channel of font buffer.
02015                     // Otherwise, just copy the contents.
02016                     if (alpha == 0x00)
02017                         destScanline[x - devRect.x()] = color | 0xff000000;
02018                     else
02019                         destScanline[x - devRect.x()] = color;
02020                 }
02021             }
02022         } else {
02023             d->fontRasterBuffer->resetBuffer(255);
02024         }
02025 
02026         // Draw the text item
02027         if (clearType) {
02028             COLORREF cf = RGB(qRed(penColor), qGreen(penColor), qBlue(penColor));
02029             SelectObject(d->fontRasterBuffer->hdc(), CreateSolidBrush(cf));
02030             SelectObject(d->fontRasterBuffer->hdc(), CreatePen(PS_SOLID, 1, cf));
02031             SetTextColor(d->fontRasterBuffer->hdc(), cf);
02032         }
02033 
02034 
02035         qt_draw_text_item(QPointF(leftBearingReserve, ti.ascent.toReal()), ti,
02036                           d->fontRasterBuffer->hdc(), false,
02037                           QMatrix(d->matrix.m11(), d->matrix.m12(), d->matrix.m21(),
02038                           d->matrix.m22(), 0, 0), topLeft);
02039 
02040         if (clearType) {
02041             DeleteObject(SelectObject(d->fontRasterBuffer->hdc(),GetStockObject(NULL_BRUSH)));
02042             DeleteObject(SelectObject(d->fontRasterBuffer->hdc(),GetStockObject(BLACK_PEN)));
02043         }
02044 
02045         // Clean up alpha channel
02046         if (clearType) {
02047             for (int y=ymin; y<ymax; ++y) {
02048                 QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y());
02049                 QRgb *rbScanline = (QRgb *) d->rasterBuffer->scanLine(y);
02050                 for (int x=xmin; x<xmax; ++x) {
02051                     // If alpha is 0, then Windows has drawn text on top of the pixel, so set
02052                     // the pixel to opaque. Otherwise, Windows has not touched the pixel, so
02053                     // we can set it to transparent so the background shines through instead.
02054                     switch (qAlpha(scanline[x - devRect.x()])) {
02055                     case 0x0:
02056                         // Special case: If Windows has drawn on top of a transparent pixel, then
02057                         // we bail out. This is an attempt at avoiding the problem where Windows
02058                         // has no background to use for composition, but also minimizing the
02059                         // number of cases hit by the fall back.
02060                         // ### This is far from optimal.
02061                         if (!brokenRasterBufferAlpha && qAlpha(rbScanline[x]) == 0) {
02062                             return drawTextInFontBuffer(devRect, xmin, ymin, xmax, ymax, textItem,
02063                                 false, leftBearingReserve, topLeft);
02064                         }
02065                         scanline[x - devRect.x()] |= 0xff000000;
02066                         break ;
02067                     default: scanline[x - devRect.x()] = 0x0; break ;
02068                     };
02069                 }
02070             }
02071         }
02072     }
02073 
02074     return clearType;
02075 }
02076 #endif // Q_WS_WIN
02077 
02078 
02082 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
02083 {
02084     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
02085 
02086 #ifdef QT_DEBUG_DRAW
02087     printf(" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
02088            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
02089 #endif
02090     Q_D(QRasterPaintEngine);
02091 #if defined(Q_WS_WIN)
02092 
02093     if (!d->penData.blend)
02094         return;
02095 
02096     if (QT_WA_INLINE(false, d->txop >= QPainterPrivate::TxScale)) {
02097         QPaintEngine::drawTextItem(p, textItem);
02098         return;
02099     }
02100 
02101     // Only support cleartype for solid pens, 32 bit target buffers and when the pen color is
02102     // opaque
02103     bool clearType = d->clear_type_text
02104                      && d->penData.type == QSpanData::Solid
02105                      && d->deviceDepth == 32
02106                      &&  qAlpha(d->penData.solid.color) == 255;
02107 
02108 
02109     QFixed x_buffering = ti.ascent;
02110 
02111     // Hack to reserve some space on the left side of the string in case
02112     // the character has a large negative bearing (e.g. it should be drawn on top
02113     // of the previous character)
02114     qreal leftBearingReserve = ti.fontEngine->maxCharWidth();
02115     qreal bufferWidth = (ti.width + x_buffering).toReal() + leftBearingReserve;
02116     qreal bufferHeight = (ti.ascent + ti.descent + 1).toReal();
02117 
02118     QMatrix m(d->matrix.m11(), d->matrix.m12(), d->matrix.m21(), d->matrix.m22(), 0, 0);
02119     QRectF logRect(0, 0, bufferWidth, bufferHeight);
02120     QPointF topLeft = m.mapRect(logRect).topLeft();
02121 
02122     logRect.moveTo(p.x() - leftBearingReserve, p.y() - ti.ascent.toReal());
02123     QRect devRect = d->matrix.mapRect(logRect).toRect();
02124     if(devRect.width() == 0 || devRect.height() == 0)
02125         return;
02126 
02127     d->fontRasterBuffer->prepare(devRect.width(), devRect.height());
02128 
02129     // Boundaries
02130     int ymax = qMin(devRect.y() + devRect.height(), d->rasterBuffer->height());
02131     int ymin = qMax(devRect.y(), 0);
02132     int xmax = qMin(devRect.x() + devRect.width(), d->rasterBuffer->width());
02133     int xmin = qMax(devRect.x(), 0);
02134 
02135     QClipData *clip = d->rasterBuffer->clipEnabled ? d->rasterBuffer->clip : 0;
02136     if (clip) {
02137         xmin = qMax(xmin, clip->xmin);
02138         xmax = qMin(xmax, clip->xmax);
02139         ymin = qMax(ymin, clip->ymin);
02140         ymax = qMin(ymax, clip->ymax);
02141     }
02142 
02143     if (xmax - xmin <= 0 || ymax - ymin <= 0)
02144         return;
02145 
02146     // Fill the font raster buffer with text
02147     clearType = drawTextInFontBuffer(devRect, xmin, ymin, xmax, ymax, textItem,
02148                                      clearType, leftBearingReserve,
02149                                      topLeft);
02150 
02151     const int NSPANS = 256;
02152     QSpan spans[NSPANS];
02153     int current = 0;
02154 
02155     if (d->mono_surface) {
02156         for (int y=ymin; y<ymax; ++y) {
02157             QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
02158             // Generate spans for this y coord
02159             for (int x = xmin; x<xmax; ) {
02160                 // Skip those with 0 coverage (black on white so inverted)
02161                 while (x < xmax && qBlue(scanline[x]) > 0x80) ++x;
02162                 if (x >= xmax) break;
02163 
02164                 QT_FT_Span span = { x, 0, y, 255 };
02165 
02166                 // extend span until we find a different one.
02167                 while (x < xmax && qBlue(scanline[x]) < 0x80) ++x;
02168                 span.len = x - span.x;
02169                 if (current == NSPANS) {
02170                     d->penData.blend(current, spans, &d->penData);
02171                     current = 0;
02172                 }
02173                 spans[current++] = span;
02174             }
02175         }
02176     } else if (clearType) {
02177         QSpanData data;
02178         data.init(d->rasterBuffer, this);
02179         data.type = QSpanData::Texture;
02180         data.texture.type = TextureData::Plain;
02181         data.texture.imageData = d->fontRasterBuffer->buffer();
02182         data.texture.width = d->fontRasterBuffer->bytesPerLine() / 4;
02183         data.texture.height = d->fontRasterBuffer->height();
02184         data.texture.bytesPerLine = d->fontRasterBuffer->bytesPerLine();
02185         data.texture.hasAlpha = true;
02186         data.bilinear = false;
02187         data.texture.const_alpha = 255;
02188         data.texture.format = QImage::Format_ARGB32_Premultiplied;
02189         data.texture.colorTable = 0;
02190 
02191         data.dx = -devRect.x();
02192         data.dy = -devRect.y();
02193         data.adjustSpanMethods();
02194         fillRect(QRect(xmin, ymin, xmax - xmin, ymax - ymin), &data);
02195     } else if (d->clear_type_text) {
02196         for (int y=ymin; y<ymax; ++y) {
02197             QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
02198             // Generate spans for this y coord
02199             for (int x = xmin; x<xmax; ) {
02200                 // Skip those with 0 coverage (black on white so inverted)
02201                 while (x < xmax && qGray(scanline[x]) == 255) ++x;
02202                 if (x >= xmax) break;
02203 
02204                 int prev = qGray(scanline[x]);
02205                 QT_FT_Span span = { x, 0, y, 255 - prev };
02206 
02207                 // extend span until we find a different one.
02208                 while (x < xmax && qGray(scanline[x]) == prev) ++x;
02209                 span.len = x - span.x;
02210 
02211                 if (current == NSPANS) {
02212                     d->penData.blend(current, spans, &d->penData);
02213                     current = 0;
02214                 }
02215                 spans[current++] = span;
02216             }
02217         }
02218     } else {
02219         // For the noncleartype/grayscale text we can look at only one color component,
02220         // and save a bit of qGray effort...
02221         for (int y=ymin; y<ymax; ++y) {
02222             QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
02223             // Generate spans for this y coord
02224             for (int x = xmin; x<xmax; ) {
02225                 // Skip those with 0 coverage (black on white so inverted)
02226                 while (x < xmax && qBlue(scanline[x]) == 255) ++x;
02227                 if (x >= xmax) break;
02228 
02229                 int prev = qBlue(scanline[x]);
02230                 QT_FT_Span span = { x, 0, y, 255 - prev };
02231 
02232                 // extend span until we find a different one.
02233                 while (x < xmax && qBlue(scanline[x]) == prev) ++x;
02234                 span.len = x - span.x;
02235 
02236                 if (current == NSPANS) {
02237                     d->penData.blend(current, spans, &d->penData);
02238                     current = 0;
02239                 }
02240                 spans[current++] = span;
02241             }
02242         }
02243     }
02244 
02245     if (current != 0)
02246         d->penData.blend(current, spans, &d->penData);
02247 
02248     return;
02249 
02250 #elif defined Q_WS_QWS
02251     if (d->txop < QPainterPrivate::TxScale) {
02252 #ifndef QT_NO_FREETYPE
02253         if (!(ti.fontEngine->type() == QFontEngine::Freetype
02254               && static_cast<QFontEngineFT*>(ti.fontEngine)->drawAsOutline()))
02255 #endif
02256         {
02257             ti.fontEngine->draw(this, qRound(p.x()), qRound(p.y()), ti);
02258             return;
02259         }
02260     }
02261 
02262 #endif // Q_WS_WIN
02263 
02264     // Fallthrough for embedded and default for mac.
02265     bool aa = d->antialiased;
02266     d->antialiased = true;
02267     QPaintEngine::drawTextItem(p, ti);
02268     d->antialiased = aa;
02269     return;
02270 }
02271 #endif
02272 
02276 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
02277 {
02278     Q_D(QRasterPaintEngine);
02279 
02280     double pw = d->pen.widthF();
02281 
02282     if (!d->fast_pen && (d->txop > QPainterPrivate::TxTranslate || pw > 1)) {
02283         QBrush oldBrush = d->brush;
02284         d->brush = Qt::NoBrush;
02285 
02286         bool flat_pen = d->pen.capStyle() == Qt::FlatCap;
02287         if (flat_pen)
02288             d->basicStroker.setCapStyle(Qt::SquareCap);
02289 
02290         const QPointF *end = points + pointCount;
02291         while (points < end) {
02292             QPainterPath path;
02293             path.moveTo(*points);
02294             path.lineTo(points->x() + 0.001, points->y());
02295             drawPath(path);
02296             ++points;
02297         }
02298 
02299         d->brush = oldBrush;
02300 
02301         if (flat_pen)
02302             d->basicStroker.setCapStyle(Qt::FlatCap);
02303 
02304     } else {
02305         if (!d->penData.blend)
02306             return;
02307 
02308         QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
02309 
02310         QT_FT_Span span = { 0, 1, 0, 255 };
02311         const QPointF *end = points + pointCount;
02312         qreal trans_x, trans_y;
02313         int x, y;
02314         int left = 0;
02315         int right = d->deviceRect.width();
02316         int top = 0;
02317         int bottom = d->deviceRect.height();
02318         int count = 0;
02319         while (points < end) {
02320             d->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
02321             x = qFloor(trans_x);
02322             y = qFloor(trans_y);
02323             if (x >= left && x < right && y >= top && y < bottom) {
02324                 span.x = x;
02325                 span.y = y;
02326                 array[count++] = span;
02327             }
02328             ++points;
02329         }
02330 
02331         d->penData.blend(count, array.constData(), &d->penData);
02332     }
02333 }
02334 
02338 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
02339 {
02340 #ifdef QT_DEBUG_DRAW
02341     qDebug() << " - QRasterPaintEngine::drawLine()";
02342 #endif
02343     Q_D(QRasterPaintEngine);
02344     if (!d->penData.blend)
02345         return;
02346     if (d->fast_pen) {
02347         QRect bounds(0, 0, d->deviceRect.width(), d->deviceRect.height());
02348         LineDrawMode mode = d->pen.capStyle() == Qt::FlatCap
02349                             ? LineDrawNormal
02350                             : LineDrawIncludeLastPixel;
02351 
02352         int m11 = int(d->matrix.m11());
02353         int m22 = int(d->matrix.m22());
02354         int dx = int(d->matrix.dx());
02355         int dy = int(d->matrix.dy());
02356         for (int i=0; i<lineCount; ++i) {
02357             int dashOffset = 0;
02358             if (d->int_xform) {
02359                 const QLine &l = lines[i];
02360                 int x1 = l.x1() * m11 + dx;
02361                 int y1 = l.y1() * m22 + dy;
02362                 int x2 = l.x2() * m11 + dx;
02363                 int y2 = l.y2() * m22 + dy;
02364 
02365 #ifdef QT_EXPERIMENTAL_REGIONS
02366                 const QRect brect(QPoint(x1, y1), QPoint(x2, y2));
02367                 const bool unclipped = qt_region_strictContains(d->clipRegion,
02368                                                                 brect);
02369                 ProcessSpans penBlend;
02370                 if (unclipped)
02371                     penBlend = d->penData.unclipped_blend;
02372                 else
02373                     penBlend = d->penData.blend;
02374                 if (d->pen.style() == Qt::SolidLine)
02375                     drawLine_midpoint_i(x1, y1, x2, y2,
02376                                         penBlend, &d->penData, mode, bounds);
02377                 else
02378                     drawLine_midpoint_dashed_i(x1, y1, x2, y2,
02379                                                &d->pen, penBlend,
02380                                                &d->penData, mode, bounds,
02381                                                &dashOffset);
02382 #else
02383                 if (d->pen.style() == Qt::SolidLine)
02384                     drawLine_midpoint_i(x1, y1, x2, y2,
02385                                         d->penData.blend, &d->penData, mode, bounds);
02386                 else
02387                     drawLine_midpoint_dashed_i(x1, y1, x2, y2,
02388                                                &d->pen, d->penData.blend,
02389                                                &d->penData, mode, bounds,
02390                                                &dashOffset);
02391 #endif
02392             } else {
02393                 QLineF line = lines[i] * d->matrix;
02394 #ifdef QT_EXPERIMENTAL_REGIONS
02395                 const QRect brect(QPoint(int(line.x1()), int(line.y1())),
02396                                   QPoint(int(line.x2()), int(line.y2())));
02397                 const bool unclipped = qt_region_strictContains(d->clipRegion,
02398                                                                 brect);
02399                 ProcessSpans penBlend;
02400                 if (unclipped)
02401                     penBlend = d->penData.unclipped_blend;
02402                 else
02403                     penBlend = d->penData.blend;
02404                 if (d->pen.style() == Qt::SolidLine)
02405                     drawLine_midpoint_i(int(line.x1()), int(line.y1()),
02406                                         int(line.x2()), int(line.y2()),
02407                                         penBlend, &d->penData, mode, bounds);
02408                 else
02409                     drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
02410                                                int(line.x2()), int(line.y2()),
02411                                                &d->pen, penBlend,
02412                                                &d->penData, mode, bounds,
02413                                                &dashOffset);
02414 #else
02415                 if (d->pen.style() == Qt::SolidLine)
02416                     drawLine_midpoint_i(int(line.x1()), int(line.y1()),
02417                                         int(line.x2()), int(line.y2()),
02418                                         d->penData.blend, &d->penData, mode, bounds);
02419                 else
02420                     drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
02421                                                int(line.x2()), int(line.y2()),
02422                                                &d->pen, d->penData.blend,
02423                                                &d->penData, mode, bounds,
02424                                                &dashOffset);
02425 #endif
02426             }
02427         }
02428     } else {
02429         QPaintEngine::drawLines(lines, lineCount);
02430     }
02431 }
02432 
02436 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
02437 {
02438 #ifdef QT_DEBUG_DRAW
02439     qDebug() << " - QRasterPaintEngine::drawLine()";
02440 #endif
02441     Q_D(QRasterPaintEngine);
02442     if (!d->penData.blend)
02443         return;
02444     if (d->fast_pen) {
02445         QRect bounds(0, 0, d->deviceRect.width(), d->deviceRect.height());
02446         LineDrawMode mode = d->pen.capStyle() == Qt::FlatCap
02447                             ? LineDrawNormal
02448                             : LineDrawIncludeLastPixel;
02449         for (int i=0; i<lineCount; ++i) {
02450             QLineF line = lines[i] * d->matrix;
02451             int dashOffset = 0;
02452 #ifdef QT_EXPERIMENTAL_REGIONS
02453             const QRect brect(QPoint(int(line.x1()), int(line.y1())),
02454                               QPoint(int(line.x2()), int(line.y2())));
02455             const bool unclipped = qt_region_strictContains(d->clipRegion,
02456                                                             brect);
02457             ProcessSpans penBlend;
02458             if (unclipped)
02459                 penBlend = d->penData.unclipped_blend;
02460             else
02461                 penBlend = d->penData.blend;
02462             if (d->pen.style() == Qt::SolidLine)
02463                 drawLine_midpoint_i(brect.left(), brect.top(),
02464                                     brect.right(), brect.bottom(),
02465                                     penBlend, &d->penData, mode, bounds);
02466             else
02467                 drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
02468                                            int(line.x2()), int(line.y2()),
02469                                            &d->pen,
02470                                            penBlend, &d->penData, mode,
02471                                            bounds, &dashOffset);
02472 #else
02473             if (d->pen.style() == Qt::SolidLine)
02474                 drawLine_midpoint_i(int(line.x1()), int(line.y1()),
02475                                     int(line.x2()), int(line.y2()),
02476                                     d->penData.blend, &d->penData, mode, bounds);
02477             else
02478                 drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
02479                                            int(line.x2()), int(line.y2()),
02480                                            &d->pen,
02481                                            d->penData.blend, &d->penData, mode,
02482                                            bounds, &dashOffset);
02483 #endif
02484         }
02485     } else {
02486         QPaintEngine::drawLines(lines, lineCount);
02487     }
02488 }
02489 
02490 
02491 // A little helper macro to get a better approximation of dimensions.
02492 // If we have a rect that starting at 0.5 of width 3.5 it should span
02493 // 4 pixels.
02494 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
02495 
02499 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
02500 {
02501     Q_D(QRasterPaintEngine);
02502     if (!d->brushData.blend && !d->penData.blend)
02503         return;
02504 
02505     const QRectF r = d->matrix.mapRect(rect);
02506     if (d->fast_pen
02507         && (d->pen.style() == Qt::SolidLine || d->pen.style() == Qt::NoPen)
02508         && qMax(r.width(), r.height()) < 128 // integer math breakdown
02509         && d->txop <= QPainterPrivate::TxScale) // no shear
02510     {
02511         const QRect devRect(0, 0, d->deviceRect.width(), d->deviceRect.height());
02512 #ifdef QT_EXPERIMENTAL_REGIONS
02513         const QRect brect = QRect(int(r.x()), int(r.y()),
02514                                   int_dim(r.x(), r.width()),
02515                                   int_dim(r.y(), r.height()));
02516         const bool unclipped = qt_region_strictContains(d->clipRegion, brect);
02517         ProcessSpans penBlend;
02518         ProcessSpans brushBlend;
02519         if (unclipped) {
02520             penBlend = d->penData.unclipped_blend;
02521             brushBlend = d->brushData.unclipped_blend;
02522         } else {
02523             penBlend = d->penData.blend;
02524             brushBlend = d->brushData.blend;
02525         }
02526         drawEllipse_midpoint_i(brect, devRect, penBlend, brushBlend,
02527                                &d->penData, &d->brushData);
02528 #else
02529         drawEllipse_midpoint_i(QRect(int(r.x()), int(r.y()),
02530                                      int_dim(r.x(), r.width()), int_dim(r.y(), r.height())),
02531                                devRect,
02532                                d->penData.blend, d->brushData.blend,
02533                                &d->penData, &d->brushData);
02534 #endif
02535         return;
02536     }
02537 
02538     if (d->brushData.blend) {
02539         QPointF controlPoints[12];
02540         int point_count = 0;
02541         QPointF start = qt_curves_for_arc(rect, 0, 360, controlPoints, &point_count);
02542 
02543         Q_ASSERT(point_count == 12); // a perfect circle...
02544 
02545         d->outlineMapper->beginOutline(Qt::WindingFill);
02546         d->outlineMapper->moveTo(start);
02547         for (int i=0; i<point_count; i+=3) {
02548             d->outlineMapper->curveTo(controlPoints[i], controlPoints[i+1], controlPoints[i+2]);
02549         }
02550         d->outlineMapper->endOutline();
02551 
02552         d->rasterize(d->outlineMapper->outline(), d->brushData.blend, &d->brushData, d->rasterBuffer);
02553     }
02554 
02555     if (d->penData.blend) {
02556         qreal width = d->pen.widthF();
02557         d->outlineMapper->beginOutline(Qt::WindingFill);
02558         if (width == 0) {
02559             d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
02560             d->stroker->strokeEllipse(rect, d->outlineMapper, d->matrix);
02561         } else {
02562             d->outlineMapper->setMatrix(d->matrix, d->txop);
02563             d->stroker->strokeEllipse(rect, d->outlineMapper, QMatrix());
02564         }
02565         d->outlineMapper->endOutline();
02566 
02567         d->rasterize(d->outlineMapper->outline(), d->penData.blend, &d->penData, d->rasterBuffer);
02568 
02569         d->outlineMapper->setMatrix(d->matrix, d->txop);
02570     }
02571 }
02572 
02576 #ifdef Q_WS_MAC
02577 CGContextRef
02578 QRasterPaintEngine::macCGContext() const
02579 {
02580     Q_D(const QRasterPaintEngine);
02581     return d->rasterBuffer->macCGContext();
02582 }
02583 #endif
02584 
02588 #ifdef Q_WS_WIN
02589 HDC QRasterPaintEngine::getDC() const
02590 {
02591     Q_D(const QRasterPaintEngine);
02592     return d->rasterBuffer->hdc();
02593 }
02594 
02598 void QRasterPaintEngine::releaseDC(HDC) const
02599 {
02600 }
02601 
02605 void QRasterPaintEngine::disableClearType()
02606 {
02607     Q_D(QRasterPaintEngine);
02608     d->clear_type_text = false;
02609     d->fontRasterBuffer->setupHDC(d->clear_type_text);
02610 }
02611 
02612 #endif
02613 
02617 QPoint QRasterPaintEngine::coordinateOffset() const
02618 {
02619     Q_D(const QRasterPaintEngine);
02620     return QPoint(d->deviceRect.x(), d->deviceRect.y());
02621 }
02622 
02633 #ifdef Q_WS_QWS
02634 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
02635 {
02636     Q_UNUSED(spans);
02637     Q_UNUSED(count);
02638     Q_UNUSED(color);
02639     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
02640            "a non memory-mapped device");
02641 }
02642 
02660 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
02661                                         int x, int y, int length, uint const_alpha)
02662 {
02663     Q_UNUSED(buffer);
02664     Q_UNUSED(bufsize);
02665     Q_UNUSED(x);
02666     Q_UNUSED(y);
02667     Q_UNUSED(length);
02668     Q_UNUSED(const_alpha);
02669     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
02670            "a non memory-mapped device");
02671 }
02672 #endif // Q_WS_QWS
02673 
02674 void QRasterPaintEnginePrivate::drawBitmap(const QPointF &pos, const QPixmap &pm, QSpanData *fg)
02675 {
02676     Q_ASSERT(fg);
02677     if (!fg->blend)
02678         return;
02679 
02680     const QImage image = pm.toImage();
02681     Q_ASSERT(image.depth() == 1);
02682 
02683     const int spanCount = 256;
02684     QT_FT_Span spans[spanCount];
02685     int n = 0;
02686 
02687     // Boundaries
02688     int w = pm.width();
02689     int h = pm.height();
02690     int ymax = qMin(qRound(pos.y() + h), rasterBuffer->height());
02691     int ymin = qMax(qRound(pos.y()), 0);
02692     int xmax = qMin(qRound(pos.x() + w), rasterBuffer->width());
02693     int xmin = qMax(qRound(pos.x()), 0);
02694 
02695     int x_offset = xmin - qRound(pos.x());
02696 
02697 #if defined (BITMAPS_ARE_MSB)
02698     QImage::Format format = image.format();
02699 #endif
02700     for (int y = ymin; y < ymax; ++y) {
02701         const uchar *src = image.scanLine(y - qRound(pos.y()));
02702 #if defined (BITMAPS_ARE_MSB)
02703         if (format == QImage::Format_MonoLSB) {
02704 #endif
02705             for (int x = 0; x < xmax - xmin; ++x) {
02706                 int src_x = x + x_offset;
02707                 uchar pixel = src[src_x >> 3];
02708                 if (!pixel) {
02709                     x += 7 - (x%8);
02710                     continue;
02711                 }
02712                 if (pixel & (0x1 << (src_x & 7))) {
02713                     spans[n].x = xmin + x;
02714                     spans[n].y = y;
02715                     spans[n].coverage = 255;
02716                     int len = 1;
02717                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
02718                         ++src_x;
02719                         ++len;
02720                     }
02721                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
02722                     x += len;
02723                     ++n;
02724                     if (n == spanCount) {
02725                         fg->blend(n, spans, fg);
02726                         n = 0;
02727                     }
02728                 }
02729             }
02730 #if defined (BITMAPS_ARE_MSB)
02731         } else {
02732             for (int x = 0; x < xmax - xmin; ++x) {
02733                 int src_x = x + x_offset;
02734                 uchar pixel = src[src_x >> 3];
02735                 if (!pixel) {
02736                     x += 7 - (x%8);
02737                     continue;
02738                 }
02739                 if (pixel & (0x80 >> (x & 7))) {
02740                     spans[n].x = xmin + x;
02741                     spans[n].y = y;
02742                     spans[n].coverage = 255;
02743                     int len = 1;
02744                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
02745                         ++src_x;
02746                         ++len;
02747                     }
02748                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
02749                     x += len;
02750                     ++n;
02751                     if (n == spanCount) {
02752                         fg->blend(n, spans, fg);
02753                         n = 0;
02754                     }
02755                 }
02756             }
02757         }
02758 #endif
02759     }
02760     if (n) {
02761         fg->blend(n, spans, fg);
02762         n = 0;
02763     }
02764 }
02765 
02766 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
02767 {
02768     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
02769 
02770     // ### buffer overflow possible
02771     const int BUFFER_SIZE = 4096;
02772     int buffer[BUFFER_SIZE];
02773     int *b = buffer;
02774     int bsize = BUFFER_SIZE;
02775 
02776     for (int y = 0; y < c1->clipSpanHeight; ++y) {
02777         const QSpan *c1_spans = c1->clipLines[y].spans;
02778         int c1_count = c1->clipLines[y].count;
02779         const QSpan *c2_spans = c2->clipLines[y].spans;
02780         int c2_count = c2->clipLines[y].count;
02781 
02782         if (c1_count == 0 && c2_count == 0)
02783             continue;
02784         if (c1_count == 0) {
02785             result->appendSpans(c2_spans, c2_count);
02786             continue;
02787         } else if (c2_count == 0) {
02788             result->appendSpans(c1_spans, c1_count);
02789             continue;
02790         }
02791 
02792         // we need to merge the two
02793 
02794         // find required length
02795         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
02796                        c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
02797         if (max > bsize) {
02798             b = (int *)realloc(bsize == BUFFER_SIZE ? 0 : b, max*sizeof(int));
02799             bsize = max;
02800         }
02801         memset(buffer, 0, BUFFER_SIZE * sizeof(int));
02802 
02803         // Fill with old spans.
02804         for (int i = 0; i < c1_count; ++i) {
02805             const QSpan *cs = c1_spans + i;
02806             for (int j=cs->x; j<cs->x + cs->len; ++j)
02807                 buffer[j] = cs->coverage;
02808         }
02809 
02810         // Fill with new spans
02811         for (int i = 0; i < c2_count; ++i) {
02812             const QSpan *cs = c2_spans + i;
02813             for (int j = cs->x; j < cs->x + cs->len; ++j) {
02814                 buffer[j] += cs->coverage;
02815                 if (buffer[j] > 255)
02816                     buffer[j] = 255;
02817             }
02818         }
02819 
02820         int x = 0;
02821         while (x<max) {
02822 
02823             // Skip to next span
02824             while (x < max && buffer[x] == 0) ++x;
02825             if (x >= max) break;
02826 
02827             int sx = x;
02828             int coverage = buffer[x];
02829 
02830             // Find length of span
02831             while (x < max && buffer[x] == coverage)
02832                 ++x;
02833 
02834             result->appendSpan(sx, x - sx, y, coverage);
02835         }
02836     }
02837     if (b != buffer)
02838         free(b);
02839 }
02840 
02841 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
02842                                           ProcessSpans callback,
02843                                           void *userData, QRasterBuffer *rasterBuffer)
02844 {
02845     if (!callback || !outline)
02846         return;
02847 
02848     void *data = userData;
02849 
02850     QT_FT_BBox clip_box = { 0, 0, deviceRect.width(), deviceRect.height() };
02851     if (rasterBuffer && rasterBuffer->clipEnabled && rasterBuffer->clip) {
02852         Q_ASSERT(((QSpanData *)userData)->rasterBuffer == rasterBuffer);
02853         clip_box.xMin = qMax((int)clip_box.xMin, rasterBuffer->clip->xmin);
02854         clip_box.xMax = qMin((int)clip_box.xMax, rasterBuffer->clip->xmax);
02855         if (antialiased)
02856             // ### Fixme: The black raster gives drawing errors when you try to
02857             // move ymin to something greater 0.
02858             clip_box.yMin = qMax((int)clip_box.yMin, rasterBuffer->clip->ymin);
02859         clip_box.yMax = qMin((int)clip_box.yMax, rasterBuffer->clip->ymax);
02860         Q_ASSERT(callback == qt_span_fill_clipped);
02861     }
02862 
02863     QT_FT_Raster_Params rasterParams;
02864     rasterParams.target = 0;
02865     rasterParams.source = outline;
02866     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
02867     rasterParams.gray_spans = 0;
02868     rasterParams.black_spans = 0;
02869     rasterParams.bit_test = 0;
02870     rasterParams.bit_set = 0;
02871     rasterParams.user = data;
02872     rasterParams.clip_box = clip_box;
02873 
02874     bool done = false;
02875     int error;
02876 
02877     while (!done) {
02878 
02879         if (antialiased) {
02880             rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
02881             rasterParams.gray_spans = callback;
02882             error = qt_ft_grays_raster.raster_render(*grayRaster, &rasterParams);
02883         } else {
02884             rasterParams.flags |= QT_FT_RASTER_FLAG_DIRECT;
02885             rasterParams.black_spans = callback;
02886             error = qt_ft_standard_raster.raster_render(*blackRaster, &rasterParams);
02887         }
02888 
02889         // Out of memory, reallocate some more and try again...
02890         if (error == -6) { // -6 is Result_err_OutOfMemory
02891             int new_size = rasterPoolSize * 2;
02892             if (new_size > 1024 * 1024) {
02893                 qWarning("QPainter: Rasterization of primitive failed");
02894                 return;
02895             }
02896 
02897 #if defined(Q_WS_WIN64)
02898             _aligned_free(rasterPoolBase);
02899 #else
02900             free(rasterPoolBase);
02901 #endif
02902 
02903             rasterPoolSize = new_size;
02904             rasterPoolBase =
02905 #if defined(Q_WS_WIN64)
02906                 (unsigned char *) _aligned_malloc(rasterPoolSize, __alignof(void*));
02907 #else
02908             (unsigned char *) malloc(rasterPoolSize);
02909 #endif
02910 
02911             qt_ft_grays_raster.raster_new(0, grayRaster);
02912             qt_ft_grays_raster.raster_reset(*grayRaster, rasterPoolBase, rasterPoolSize);
02913 
02914             qt_ft_standard_raster.raster_new(0, blackRaster);
02915             qt_ft_standard_raster.raster_reset(*blackRaster, rasterPoolBase, rasterPoolSize);
02916 
02917         } else {
02918             done = true;
02919         }
02920     }
02921 }
02922 
02923 
02924 void QRasterPaintEnginePrivate::updateClip_helper(const QPainterPath &path, Qt::ClipOperation op)
02925 {
02926 #ifdef QT_DEBUG_DRAW
02927     QRectF bounds = path.boundingRect();
02928     qDebug() << " --- updateClip_helper(), op=" << op << ", bounds=" << bounds
02929              << rasterBuffer->clipEnabled << rasterBuffer->clip;
02930 #endif
02931     if (op == Qt::IntersectClip && !rasterBuffer->clipEnabled)
02932         op = Qt::ReplaceClip;
02933 
02934     if (op == Qt::NoClip) {
02935         rasterBuffer->resetClip();
02936         rasterBuffer->clipEnabled = false;
02937         goto end;
02938     } else if (path.isEmpty()) {
02939         if (op == Qt::ReplaceClip || op == Qt::IntersectClip) {
02940             rasterBuffer->resetClip();
02941 #ifdef QT_EXPERIMENTAL_REGIONS
02942             rasterBuffer->clip = new QClipData(rasterBuffer->height());
02943 #else
02944             QClipData *clip = rasterBuffer->clip = new QClipData(rasterBuffer->height());
02945             for (int i=0; i<clip->clipSpanHeight; ++i) {
02946                 clip->appendSpan(0, i, 0, 0);
02947             }
02948             clip->fixup();
02949 #endif
02950         }
02951     } else if (op == Qt::ReplaceClip) {
02952         rasterBuffer->resetClip();
02953     } else if (op == Qt::IntersectClip && !rasterBuffer->clip) {
02954         return;
02955     }
02956 
02957     rasterBuffer->clipEnabled = true;
02958     if (!path.isEmpty()) {
02959         QClipData *newClip = new QClipData(rasterBuffer->height());
02960         ClipData clipData = { rasterBuffer->clip, newClip, op };
02961         rasterize(outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
02962         newClip->fixup();
02963 
02964         if (op == Qt::UniteClip) {
02965             // merge clips
02966             QClipData *result = new QClipData(rasterBuffer->height());
02967             qt_merge_clip(rasterBuffer->clip, newClip, result);
02968             result->fixup();
02969             delete newClip;
02970             newClip = result;
02971         }
02972 
02973         delete rasterBuffer->clip;
02974         rasterBuffer->clip = newClip;
02975     }
02976 end:
02977     penData.adjustSpanMethods();
02978     brushData.adjustSpanMethods();
02979 }
02980 
02981 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
02982 {
02983     Q_ASSERT(image.depth() == 1);
02984 
02985     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
02986     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
02987 
02988     QRgb fg = PREMUL(color.rgba());
02989     QRgb bg = 0;
02990 
02991     int height = sourceImage.height();
02992     int width = sourceImage.width();
02993     for (int y=0; y<height; ++y) {
02994         uchar *source = sourceImage.scanLine(y);
02995         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
02996         for (int x=0; x < width; ++x)
02997             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
02998     }
02999     return dest;
03000 }
03001 
03002 QRasterBuffer::~QRasterBuffer()
03003 {
03004     delete clip;
03005 
03006 #if defined (Q_WS_MAC)
03007     if(m_ctx) {
03008         CGContextRelease(m_ctx);
03009         m_ctx = 0;
03010     }
03011     if(m_data) {
03012         CGImageRelease(m_data);
03013         m_data = 0;
03014     }
03015 #endif
03016 
03017 #if defined (Q_WS_WIN)
03018     if (m_bitmap || m_hdc) {
03019         Q_ASSERT(m_hdc);
03020         Q_ASSERT(m_bitmap);
03021         DeleteObject(m_hdc);
03022         DeleteObject(m_bitmap);
03023     }
03024 #endif
03025 }
03026 
03027 void QRasterBuffer::init()
03028 {
03029     clipEnabled = false;
03030     disabled_clip = 0;
03031 
03032     compositionMode = QPainter::CompositionMode_SourceOver;
03033     delete clip;
03034     clip = 0;
03035     format = QImage::Format_ARGB32_Premultiplied;
03036     drawHelper = qDrawHelper + QImage::Format_ARGB32_Premultiplied;
03037 }
03038 
03039 
03040 #if defined(Q_WS_MAC)
03041 CGContextRef
03042 QRasterBuffer::macCGContext() const
03043 {
03044     if(!m_ctx && m_data) {
03045 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
03046         uint flags = CGImageGetAlphaInfo(m_data);
03047         CGBitmapInfo (*CGImageGetBitmapInfo_ptr)(CGImageRef) = CGImageGetBitmapInfo;
03048         if(CGImageGetBitmapInfo_ptr)
03049             flags |= (*CGImageGetBitmapInfo_ptr)(m_data);
03050 #else
03051         CGImageAlphaInfo flags = CGImageGetAlphaInfo(m_data);
03052 #endif
03053         CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
03054         m_ctx = CGBitmapContextCreate(m_buffer, m_width, m_height, 8, m_width * 4, colorspace,
03055                                       flags);
03056         CGColorSpaceRelease(colorspace);
03057         if(!m_ctx)
03058             qWarning("QPaintDevice: Unable to create context for rasterbuffer (%d/%d)",
03059                      m_width, m_height);
03060         CGContextTranslateCTM(m_ctx, 0, m_height);
03061         CGContextScaleCTM(m_ctx, 1, -1);
03062     }
03063     return m_ctx;
03064 }
03065 #endif
03066 
03067 #if defined(Q_WS_WIN)
03068 void QRasterBuffer::setupHDC(bool clear_type)
03069 {
03070     if (!clear_type) {
03071         SelectObject(m_hdc, GetStockObject(BLACK_BRUSH));
03072         SelectObject(m_hdc, GetStockObject(BLACK_PEN));
03073         SetTextColor(m_hdc, RGB(0, 0, 0));
03074     }
03075 }
03076 #endif
03077 
03078 void QRasterBuffer::prepare(int w, int h)
03079 {
03080     if (w<=m_width && h<=m_height) {
03081 #ifdef Q_WS_MAC
03082         memset(m_buffer, 0, m_width*h*sizeof(uint));
03083 #endif
03084         return;
03085     }
03086 
03087     prepareBuffer(w, h);
03088 
03089     m_width = w;
03090     m_height = h;
03091     bytes_per_line = 4*m_width;
03092 
03093 }
03094 
03095 
03096 void QRasterBuffer::prepare(QImage *image)
03097 {
03098     int depth = image->depth();
03099     m_buffer = (uchar *)image->bits();
03100     m_width = image->width();
03101     m_height = image->height();
03102     bytes_per_line = 4*(depth == 32 ? m_width : (m_width*depth + 31)/32);
03103 
03104     format = image->format();
03105     drawHelper = qDrawHelper + format;
03106 }
03107 
03108 void QRasterBuffer::resetBuffer(int