00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00090
00091
00092
00093
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
00118
00119
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
00126
00127 const int QT_RASTER_COORD_LIMIT = 16385;
00128
00129 struct QRasterFloatPoint {
00130 qreal x;
00131 qreal y;
00132 };
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
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
00225
00226
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;
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
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
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
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
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
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
00445
00446
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
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
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
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
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
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
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 *);
00933 extern void qt_mac_clip_cg(CGContextRef, const QRegion &, const QPoint *, CGAffineTransform *);
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);
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
00995
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
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
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
01110
01111
01112
01113
01114 if (!d->baseClip.isEmpty()) {
01115 if (!state.isClipEnabled()) {
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 {
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
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
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
01455 if (d->brushData.blend && mode != PolylineMode) {
01456
01457
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
01468 d->rasterize(d->outlineMapper->outline(), d->brushData.blend, &d->brushData, d->rasterBuffer);
01469 }
01470
01471
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
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
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
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
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
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
01571 if (d->brushData.blend && mode != PolylineMode) {
01572
01573
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
01584 d->rasterize(d->outlineMapper->outline(), d->brushData.blend, &d->brushData, d->rasterBuffer);
01585 }
01586
01587
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
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
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);
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
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
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
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
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
01908
01909
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
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
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
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
01994 QRgb penColor = 0;
01995 bool brokenRasterBufferAlpha = false;
01996 if (clearType) {
01997 penColor = d->penData.solid.color;
01998
01999
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
02007
02008
02009 int alpha = qAlpha(color);
02010 if (qRed(color) > alpha || qGreen(color) > alpha || qBlue(color) > alpha)
02011 brokenRasterBufferAlpha = true;
02012
02013
02014
02015
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
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
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
02052
02053
02054 switch (qAlpha(scanline[x - devRect.x()])) {
02055 case 0x0:
02056
02057
02058
02059
02060
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
02102
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
02112
02113
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
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
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
02159 for (int x = xmin; x<xmax; ) {
02160
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
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
02199 for (int x = xmin; x<xmax; ) {
02200
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
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
02220
02221 for (int y=ymin; y<ymax; ++y) {
02222 QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
02223
02224 for (int x = xmin; x<xmax; ) {
02225
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
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
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
02492
02493
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
02509 && d->txop <= QPainterPrivate::TxScale)
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);
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
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
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
02793
02794
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
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
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
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
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
02857
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
02890 if (error == -6) {
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
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