1 /****************************************************************************
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include <QtCore/qglobal.h>
43 #include <QtCore/qmutex.h>
45 #define QT_FT_BEGIN_HEADER
46 #define QT_FT_END_HEADER
48 #include <private/qrasterdefs_p.h>
49 #include <private/qgrayraster_p.h>
51 #include <qpainterpath.h>
58 #if defined (Q_WS_X11)
59 # include <private/qfontengine_ft_p.h>
62 // #include <private/qdatabuffer_p.h>
63 // #include <private/qpainter_p.h>
64 #include <private/qmath_p.h>
65 #include <private/qtextengine_p.h>
66 #include <private/qfontengine_p.h>
67 #include <private/qpixmap_raster_p.h>
68 // #include <private/qpolygonclipper_p.h>
69 // #include <private/qrasterizer_p.h>
70 #include <private/qimage_p.h>
71 #include <private/qstatictext_p.h>
72 #include <private/qcosmeticstroker_p.h>
73 #include "qmemrotate_p.h"
75 #include "qpaintengine_raster_p.h"
76 // #include "qbezier_p.h"
77 #include "qoutlinemapper_p.h"
80 # include <qt_windows.h>
81 # include <qvarlengtharray.h>
82 # include <private/qfontengine_p.h>
83 # if defined(Q_OS_WINCE)
84 # include "qguifunctions_wince.h"
86 #elif defined(Q_WS_MAC)
87 # include <private/qt_mac_p.h>
88 # include <private/qpixmap_mac_p.h>
89 # include <private/qpaintengine_mac_p.h>
90 #elif defined(Q_WS_QWS)
91 # if !defined(QT_NO_FREETYPE)
92 # include <private/qfontengine_ft_p.h>
94 # if !defined(QT_NO_QWS_QPF2)
95 # include <private/qfontengine_qpf_p.h>
97 # include <private/qabstractfontengine_p.h>
98 #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
99 # include <private/qfontengine_s60_p.h>
100 #elif defined(Q_WS_QPA)
101 # include <private/qfontengine_ft_p.h>
104 #if defined(Q_WS_WIN64)
111 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
113 #define qreal_to_fixed_26_6(f) (int(f * 64))
114 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
115 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
117 // #define QT_DEBUG_DRAW
119 void dumpClip(int width, int height, const QClipData *clip);
122 #define QT_FAST_SPANS
125 // A little helper macro to get a better approximation of dimensions.
126 // If we have a rect that starting at 0.5 of width 3.5 it should span
128 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
130 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
131 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
134 extern bool qt_cleartype_enabled;
138 extern bool qt_applefontsmoothing_enabled;
142 /********************************************************************************
145 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
146 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
147 static void qt_span_clip(int count, const QSpan *spans, void *userData);
148 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
154 Qt::ClipOperation operation;
160 LineDrawIncludeLastPixel
163 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
164 ProcessSpans pen_func, ProcessSpans brush_func,
165 QSpanData *pen_data, QSpanData *brush_data);
167 struct QRasterFloatPoint {
173 static const QRectF boundingRect(const QPointF *points, int pointCount)
175 const QPointF *e = points;
176 const QPointF *last = points + pointCount;
177 qreal minx, maxx, miny, maxy;
178 minx = maxx = e->x();
179 miny = maxy = e->y();
183 else if (e->x() > maxx)
187 else if (e->y() > maxy)
190 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
194 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
195 return (elementCount == 5 // 5-point polygon, check for closed rect
196 && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
197 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
198 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
199 && pts[0] < pts[4] && pts[1] < pts[5]
201 (elementCount == 4 // 4-point polygon, check for unclosed rect
202 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
203 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
204 && pts[0] < pts[4] && pts[1] < pts[5]
209 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
211 ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
214 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
216 ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
219 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
220 qfixed c2x, qfixed c2y,
221 qfixed ex, qfixed ey,
224 ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
225 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
226 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
230 #if !defined(QT_NO_DEBUG) && 0
231 static void qt_debug_path(const QPainterPath &path)
233 const char *names[] = {
240 fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
241 for (int i=0; i<path.elementCount(); ++i) {
242 const QPainterPath::Element &e = path.elementAt(i);
243 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
244 fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
249 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
250 QPaintEngineExPrivate(),
257 \class QRasterPaintEngine
262 \brief The QRasterPaintEngine class enables hardware acceleration
263 of painting operations in Qt for Embedded Linux.
265 Note that this functionality is only available in
266 \l{Qt for Embedded Linux}.
268 In \l{Qt for Embedded Linux}, painting is a pure software
269 implementation. But starting with Qt 4.2, it is
270 possible to add an accelerated graphics driver to take advantage
271 of available hardware resources.
273 Hardware acceleration is accomplished by creating a custom screen
274 driver, accelerating the copying from memory to the screen, and
275 implementing a custom paint engine accelerating the various
276 painting operations. Then a custom paint device (derived from the
277 QCustomRasterPaintDevice class) and a custom window surface
278 (derived from QWSWindowSurface) must be implemented to make
279 \l{Qt for Embedded Linux} aware of the accelerated driver.
281 \note The QRasterPaintEngine class does not support 8-bit images.
282 Instead, they need to be converted to a supported format, such as
283 QImage::Format_ARGB32_Premultiplied.
285 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
286 documentation for details.
288 \sa QCustomRasterPaintDevice, QPaintEngine
292 \fn Type QRasterPaintEngine::type() const
298 \relates QRasterPaintEngine
300 A struct equivalent to QT_FT_Span, containing a position (x,
301 y), the span's length in pixels and its color/coverage (a value
302 ranging from 0 to 255).
308 Creates a raster based paint engine for operating on the given
309 \a device, with the complete set of \l
310 {QPaintEngine::PaintEngineFeature}{paint engine features and
313 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
314 : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
316 d_func()->device = device;
323 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
326 d_func()->device = device;
330 void QRasterPaintEngine::init()
332 Q_D(QRasterPaintEngine);
339 // The antialiasing raster.
340 d->grayRaster.reset(new QT_FT_Raster);
341 Q_CHECK_PTR(d->grayRaster.data());
342 if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
343 QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
346 d->rasterizer.reset(new QRasterizer);
347 d->rasterBuffer.reset(new QRasterBuffer());
348 d->outlineMapper.reset(new QOutlineMapper);
349 d->outlinemapper_xform_dirty = true;
351 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
352 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
353 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
355 d->baseClip.reset(new QClipData(d->device->height()));
356 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
358 d->image_filler.init(d->rasterBuffer.data(), this);
359 d->image_filler.type = QSpanData::Texture;
361 d->image_filler_xform.init(d->rasterBuffer.data(), this);
362 d->image_filler_xform.type = QSpanData::Texture;
364 d->solid_color_filler.init(d->rasterBuffer.data(), this);
365 d->solid_color_filler.type = QSpanData::Solid;
367 d->deviceDepth = d->device->depth();
369 d->mono_surface = false;
370 gccaps &= ~PorterDuff;
372 QImage::Format format = QImage::Format_Invalid;
374 switch (d->device->devType()) {
375 case QInternal::Pixmap:
376 qWarning("QRasterPaintEngine: unsupported for pixmaps...");
378 case QInternal::Image:
379 format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
382 case QInternal::CustomRaster:
383 d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
387 qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
393 case QImage::Format_MonoLSB:
394 case QImage::Format_Mono:
395 d->mono_surface = true;
397 case QImage::Format_ARGB8565_Premultiplied:
398 case QImage::Format_ARGB8555_Premultiplied:
399 case QImage::Format_ARGB6666_Premultiplied:
400 case QImage::Format_ARGB4444_Premultiplied:
401 case QImage::Format_ARGB32_Premultiplied:
402 case QImage::Format_ARGB32:
403 gccaps |= PorterDuff;
405 case QImage::Format_RGB32:
406 case QImage::Format_RGB444:
407 case QImage::Format_RGB555:
408 case QImage::Format_RGB666:
409 case QImage::Format_RGB888:
410 case QImage::Format_RGB16:
421 Destroys this paint engine.
423 QRasterPaintEngine::~QRasterPaintEngine()
425 Q_D(QRasterPaintEngine);
427 qt_ft_grays_raster.raster_done(*d->grayRaster.data());
433 bool QRasterPaintEngine::begin(QPaintDevice *device)
435 Q_D(QRasterPaintEngine);
437 if (device->devType() == QInternal::Pixmap) {
438 QPixmap *pixmap = static_cast<QPixmap *>(device);
439 QPixmapData *pd = pixmap->pixmapData();
440 if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
441 d->device = pd->buffer();
446 // Make sure QPaintEngine::paintDevice() returns the proper device.
449 Q_ASSERT(d->device->devType() == QInternal::Image
450 || d->device->devType() == QInternal::CustomRaster);
452 d->systemStateChanged();
454 QRasterPaintEngineState *s = state();
455 ensureOutlineMapper();
456 d->outlineMapper->m_clip_rect = d->deviceRect;
458 if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
459 d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
460 if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
461 d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
463 d->rasterizer->setClipRect(d->deviceRect);
465 s->penData.init(d->rasterBuffer.data(), this);
466 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
467 s->stroker = &d->basicStroker;
468 d->basicStroker.setClipRect(d->deviceRect);
470 s->brushData.init(d->rasterBuffer.data(), this);
471 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
473 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
475 setDirty(DirtyBrushOrigin);
478 qDebug() << "QRasterPaintEngine::begin(" << (void *) device
479 << ") devType:" << device->devType()
480 << "devRect:" << d->deviceRect;
482 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
486 #if defined(Q_WS_WIN)
487 d->isPlain45DegreeRotation = true;
491 d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
492 #if defined(Q_WS_WIN)
493 else if (qt_cleartype_enabled)
494 #elif defined (Q_WS_MAC)
495 else if (qt_applefontsmoothing_enabled)
500 QImage::Format format = static_cast<QImage *>(d->device)->format();
501 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
502 d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
504 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
506 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
515 bool QRasterPaintEngine::end()
518 Q_D(QRasterPaintEngine);
519 qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
521 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
531 void QRasterPaintEngine::releaseBuffer()
533 Q_D(QRasterPaintEngine);
534 d->rasterBuffer.reset(new QRasterBuffer);
540 QSize QRasterPaintEngine::size() const
542 Q_D(const QRasterPaintEngine);
543 return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
550 void QRasterPaintEngine::saveBuffer(const QString &s) const
552 Q_D(const QRasterPaintEngine);
553 d->rasterBuffer->bufferImage().save(s, "PNG");
560 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
562 QRasterPaintEngineState *s = state();
563 // FALCON: get rid of this line, see drawImage call below.
565 QTransform::TransformationType txop = s->matrix.type();
569 case QTransform::TxNone:
570 s->flags.int_xform = true;
573 case QTransform::TxTranslate:
574 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
575 && qreal(int(s->matrix.dy())) == s->matrix.dy();
578 case QTransform::TxScale:
579 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
580 && qreal(int(s->matrix.dy())) == s->matrix.dy()
581 && qreal(int(s->matrix.m11())) == s->matrix.m11()
582 && qreal(int(s->matrix.m22())) == s->matrix.m22();
585 default: // shear / perspective...
586 s->flags.int_xform = false;
590 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
592 ensureOutlineMapper();
595 Q_D(QRasterPaintEngine);
596 d->isPlain45DegreeRotation = false;
597 if (txop >= QTransform::TxRotate) {
598 d->isPlain45DegreeRotation =
599 (qFuzzyIsNull(matrix.m11())
600 && qFuzzyIsNull(matrix.m12() - qreal(1))
601 && qFuzzyIsNull(matrix.m21() + qreal(1))
602 && qFuzzyIsNull(matrix.m22())
605 (qFuzzyIsNull(matrix.m11() + qreal(1))
606 && qFuzzyIsNull(matrix.m12())
607 && qFuzzyIsNull(matrix.m21())
608 && qFuzzyIsNull(matrix.m22() + qreal(1))
611 (qFuzzyIsNull(matrix.m11())
612 && qFuzzyIsNull(matrix.m12() + qreal(1))
613 && qFuzzyIsNull(matrix.m21() - qreal(1))
614 && qFuzzyIsNull(matrix.m22())
624 QRasterPaintEngineState::~QRasterPaintEngineState()
626 if (flags.has_clip_ownership)
631 QRasterPaintEngineState::QRasterPaintEngineState()
643 flags.fast_pen = true;
644 flags.antialiased = false;
645 flags.bilinear = false;
646 flags.fast_text = true;
647 flags.int_xform = true;
648 flags.tx_noshear = true;
649 flags.fast_images = true;
652 flags.has_clip_ownership = false;
657 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
662 , strokeFlags(s.strokeFlags)
663 , lastBrush(s.lastBrush)
664 , brushData(s.brushData)
665 , fillFlags(s.fillFlags)
666 , pixmapFlags(s.pixmapFlags)
667 , intOpacity(s.intOpacity)
671 , flag_bits(s.flag_bits)
673 brushData.tempImage = 0;
674 penData.tempImage = 0;
675 flags.has_clip_ownership = false;
681 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
683 QRasterPaintEngineState *s;
685 s = new QRasterPaintEngineState();
687 s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
695 void QRasterPaintEngine::setState(QPainterState *s)
697 Q_D(QRasterPaintEngine);
698 QPaintEngineEx::setState(s);
699 d->rasterBuffer->compositionMode = s->composition_mode;
703 \fn QRasterPaintEngineState *QRasterPaintEngine::state()
708 \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
715 void QRasterPaintEngine::penChanged()
718 qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
720 QRasterPaintEngineState *s = state();
721 s->strokeFlags |= DirtyPen;
722 s->dirty |= DirtyPen;
728 void QRasterPaintEngine::updatePen(const QPen &pen)
730 Q_D(QRasterPaintEngine);
731 QRasterPaintEngineState *s = state();
733 qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
736 Qt::PenStyle pen_style = qpen_style(pen);
741 s->penData.clip = d->clip();
742 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
744 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
745 || pen.brush().transform().type() >= QTransform::TxNone) {
746 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
749 // Slightly ugly handling of an uncommon case... We need to change
750 // the pen because it is reused in draw_midpoint to decide dashed
752 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
753 pen_style = Qt::SolidLine;
754 s->lastPen.setStyle(Qt::SolidLine);
757 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
758 d->basicStroker.setCapStyle(qpen_capStyle(pen));
759 d->basicStroker.setMiterLimit(pen.miterLimit());
761 qreal penWidth = qpen_widthf(pen);
763 d->basicStroker.setStrokeWidth(1);
765 d->basicStroker.setStrokeWidth(penWidth);
767 if(pen_style == Qt::SolidLine) {
768 s->stroker = &d->basicStroker;
769 } else if (pen_style != Qt::NoPen) {
771 d->dashStroker.reset(new QDashStroker(&d->basicStroker));
772 if (pen.isCosmetic()) {
773 d->dashStroker->setClipRect(d->deviceRect);
775 // ### I've seen this inverted devrect multiple places now...
776 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
777 d->dashStroker->setClipRect(clipRect);
779 d->dashStroker->setDashPattern(pen.dashPattern());
780 d->dashStroker->setDashOffset(pen.dashOffset());
781 s->stroker = d->dashStroker.data();
786 ensureState(); // needed because of tx_noshear...
787 s->flags.fast_pen = pen_style > Qt::NoPen
789 && ((pen.isCosmetic() && penWidth <= 1)
790 || (!pen.isCosmetic() && s->flags.tx_noshear && penWidth * s->txscale <= 1));
792 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
802 void QRasterPaintEngine::brushOriginChanged()
804 QRasterPaintEngineState *s = state();
806 qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
809 s->fillFlags |= DirtyBrushOrigin;
816 void QRasterPaintEngine::brushChanged()
818 QRasterPaintEngineState *s = state();
820 qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
822 s->fillFlags |= DirtyBrush;
831 void QRasterPaintEngine::updateBrush(const QBrush &brush)
834 qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
836 Q_D(QRasterPaintEngine);
837 QRasterPaintEngineState *s = state();
838 // must set clip prior to setup, as setup uses it...
839 s->brushData.clip = d->clip();
840 s->brushData.setup(brush, s->intOpacity, s->composition_mode);
841 if (s->fillFlags & DirtyTransform
842 || brush.transform().type() >= QTransform::TxNone)
843 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
844 s->lastBrush = brush;
848 void QRasterPaintEngine::updateOutlineMapper()
850 Q_D(QRasterPaintEngine);
851 d->outlineMapper->setMatrix(state()->matrix);
854 void QRasterPaintEngine::updateState()
856 QRasterPaintEngineState *s = state();
858 if (s->dirty & DirtyTransform)
859 updateMatrix(s->matrix);
861 if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
862 const QPainter::CompositionMode mode = s->composition_mode;
863 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
864 && s->intOpacity == 256
865 && (mode == QPainter::CompositionMode_Source
866 || (mode == QPainter::CompositionMode_SourceOver
867 && qAlpha(s->penData.solid.color) == 255));
877 void QRasterPaintEngine::opacityChanged()
879 QRasterPaintEngineState *s = state();
882 qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
885 s->fillFlags |= DirtyOpacity;
886 s->strokeFlags |= DirtyOpacity;
887 s->pixmapFlags |= DirtyOpacity;
888 s->dirty |= DirtyOpacity;
889 s->intOpacity = (int) (s->opacity * 256);
895 void QRasterPaintEngine::compositionModeChanged()
897 Q_D(QRasterPaintEngine);
898 QRasterPaintEngineState *s = state();
901 qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
904 s->fillFlags |= DirtyCompositionMode;
905 s->dirty |= DirtyCompositionMode;
907 s->strokeFlags |= DirtyCompositionMode;
908 d->rasterBuffer->compositionMode = s->composition_mode;
910 d->recalculateFastImages();
916 void QRasterPaintEngine::renderHintsChanged()
918 QRasterPaintEngineState *s = state();
921 qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
924 bool was_aa = s->flags.antialiased;
925 bool was_bilinear = s->flags.bilinear;
927 s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
928 s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
930 if (was_aa != s->flags.antialiased)
931 s->strokeFlags |= DirtyHints;
933 if (was_bilinear != s->flags.bilinear) {
934 s->strokeFlags |= DirtyPen;
935 s->fillFlags |= DirtyBrush;
938 Q_D(QRasterPaintEngine);
939 d->recalculateFastImages();
945 void QRasterPaintEngine::transformChanged()
947 QRasterPaintEngineState *s = state();
950 qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
953 s->fillFlags |= DirtyTransform;
954 s->strokeFlags |= DirtyTransform;
956 s->dirty |= DirtyTransform;
958 Q_D(QRasterPaintEngine);
959 d->recalculateFastImages();
965 void QRasterPaintEngine::clipEnabledChanged()
967 QRasterPaintEngineState *s = state();
970 qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
974 s->clip->enabled = s->clipEnabled;
975 s->fillFlags |= DirtyClipEnabled;
976 s->strokeFlags |= DirtyClipEnabled;
977 s->pixmapFlags |= DirtyClipEnabled;
982 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
984 rasterBuffer->prepare(device);
988 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
990 SrcOverBlendFunc func,
995 if (alpha == 0 || !clip.isValid())
998 Q_ASSERT(img.depth() >= 8);
1000 int srcBPL = img.bytesPerLine();
1001 const uchar *srcBits = img.bits();
1002 int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
1003 int iw = img.width();
1004 int ih = img.height();
1006 if (!sr.isEmpty()) {
1009 // Adjust the image according to the source offset...
1010 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1013 // adapt the x parameters
1014 int x = qRound(pt.x());
1016 int cx2 = clip.x() + clip.width();
1019 srcBits += srcSize * d;
1024 int d = x + iw - cx2;
1030 // adapt the y paremeters...
1032 int cy2 = clip.y() + clip.height();
1033 int y = qRound(pt.y());
1036 srcBits += srcBPL * d;
1041 int d = y + ih - cy2;
1047 // call the blend function...
1048 int dstSize = rasterBuffer->bytesPerPixel();
1049 int dstBPL = rasterBuffer->bytesPerLine();
1050 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1057 void QRasterPaintEnginePrivate::systemStateChanged()
1059 deviceRectUnclipped = QRect(0, 0,
1060 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1061 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1063 if (!systemClip.isEmpty()) {
1064 QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
1065 deviceRect = clippedDeviceRgn.boundingRect();
1066 baseClip->setClipRegion(clippedDeviceRgn);
1068 deviceRect = deviceRectUnclipped;
1069 baseClip->setClipRect(deviceRect);
1071 #ifdef QT_DEBUG_DRAW
1072 qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
1075 exDeviceRect = deviceRect;
1077 Q_Q(QRasterPaintEngine);
1078 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1079 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1080 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1083 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1085 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1088 Q_Q(QRasterPaintEngine);
1089 bool bilinear = q->state()->flags.bilinear;
1091 if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1092 spanData->setupMatrix(b.transform() * m, bilinear);
1094 if (m.type() <= QTransform::TxTranslate) {
1095 // specialize setupMatrix for translation matrices
1096 // to avoid needless matrix inversion
1104 spanData->dx = -m.dx();
1105 spanData->dy = -m.dy();
1106 spanData->txop = m.type();
1107 spanData->bilinear = bilinear;
1108 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1109 spanData->adjustSpanMethods();
1111 spanData->setupMatrix(m, bilinear);
1116 // #define QT_CLIPPING_RATIOS
1118 #ifdef QT_CLIPPING_RATIOS
1123 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1125 if (d->clip()->hasRectClip)
1127 if (d->clip()->hasRegionClip)
1131 if ((totalClips % 5000) == 0) {
1132 printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1133 rectClips * 100.0 / (qreal) totalClips,
1134 regionClips * 100.0 / (qreal) totalClips,
1135 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1144 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1146 if (s->flags.has_clip_ownership)
1149 s->flags.has_clip_ownership = false;
1152 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1154 s->fillFlags |= QPaintEngine::DirtyClipPath;
1155 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1156 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1158 d->solid_color_filler.clip = d->clip();
1159 d->solid_color_filler.adjustSpanMethods();
1161 #ifdef QT_DEBUG_DRAW
1162 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1171 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1173 #ifdef QT_DEBUG_DRAW
1174 qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1176 if (path.elements()) {
1177 for (int i=0; i<path.elementCount(); ++i) {
1178 qDebug() << " - " << path.elements()[i]
1179 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1182 for (int i=0; i<path.elementCount(); ++i) {
1183 qDebug() << " ---- "
1184 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1189 Q_D(QRasterPaintEngine);
1190 QRasterPaintEngineState *s = state();
1192 const qreal *points = path.points();
1193 const QPainterPath::ElementType *types = path.elements();
1195 // There are some cases that are not supported by clip(QRect)
1196 if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1197 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1198 if (s->matrix.type() <= QTransform::TxScale
1199 && ((path.shape() == QVectorPath::RectangleHint)
1200 || (isRect(points, path.elementCount())
1201 && (!types || (types[0] == QPainterPath::MoveToElement
1202 && types[1] == QPainterPath::LineToElement
1203 && types[2] == QPainterPath::LineToElement
1204 && types[3] == QPainterPath::LineToElement))))) {
1205 #ifdef QT_DEBUG_DRAW
1206 qDebug() << " --- optimizing vector clip to rect clip...";
1209 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1210 if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1215 if (op == Qt::NoClip) {
1216 qrasterpaintengine_state_setNoClip(s);
1219 QClipData *base = d->baseClip.data();
1221 // Intersect with current clip when available...
1222 if (op == Qt::IntersectClip && s->clip)
1225 // We always intersect, except when there is nothing to
1226 // intersect with, in which case we simplify the operation to
1228 Qt::ClipOperation isectOp = Qt::IntersectClip;
1230 isectOp = Qt::ReplaceClip;
1232 QClipData *newClip = new QClipData(d->rasterBuffer->height());
1233 newClip->initialize();
1234 ClipData clipData = { base, newClip, isectOp };
1235 ensureOutlineMapper();
1236 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1240 if (op == Qt::UniteClip) {
1242 QClipData *result = new QClipData(d->rasterBuffer->height());
1243 QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1244 qt_merge_clip(current, newClip, result);
1252 if (s->flags.has_clip_ownership)
1256 s->flags.has_clip_ownership = true;
1258 qrasterpaintengine_dirty_clip(d, s);
1266 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1268 #ifdef QT_DEBUG_DRAW
1269 qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1272 QRasterPaintEngineState *s = state();
1274 if (op == Qt::NoClip) {
1275 qrasterpaintengine_state_setNoClip(s);
1277 } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1278 QPaintEngineEx::clip(rect, op);
1281 } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1282 QPaintEngineEx::clip(rect, op);
1288 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1290 Q_D(QRasterPaintEngine);
1291 QRect clipRect = r & d->deviceRect;
1292 QRasterPaintEngineState *s = state();
1294 if (op == Qt::ReplaceClip || s->clip == 0) {
1296 // No current clip, hence we intersect with sysclip and be
1298 QRegion clipRegion = systemClip();
1299 QClipData *clip = new QClipData(d->rasterBuffer->height());
1301 if (clipRegion.isEmpty())
1302 clip->setClipRect(clipRect);
1304 clip->setClipRegion(clipRegion & clipRect);
1306 if (s->flags.has_clip_ownership)
1310 s->clip->enabled = true;
1311 s->flags.has_clip_ownership = true;
1313 } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1314 QClipData *base = s->clip;
1317 if (base->hasRectClip || base->hasRegionClip) {
1318 if (!s->flags.has_clip_ownership) {
1319 s->clip = new QClipData(d->rasterBuffer->height());
1320 s->flags.has_clip_ownership = true;
1322 if (base->hasRectClip)
1323 s->clip->setClipRect(base->clipRect & clipRect);
1325 s->clip->setClipRegion(base->clipRegion & clipRect);
1326 s->clip->enabled = true;
1334 qrasterpaintengine_dirty_clip(d, s);
1342 void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
1344 #ifdef QT_DEBUG_DRAW
1345 qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1348 Q_D(QRasterPaintEngine);
1350 if (region.rectCount() == 1) {
1351 clip(region.boundingRect(), op);
1355 QRasterPaintEngineState *s = state();
1356 const QClipData *clip = d->clip();
1357 const QClipData *baseClip = d->baseClip.data();
1359 if (op == Qt::NoClip) {
1360 qrasterpaintengine_state_setNoClip(s);
1361 } else if (s->matrix.type() > QTransform::TxScale
1362 || op == Qt::UniteClip
1363 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1364 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1365 QPaintEngineEx::clip(region, op);
1367 const QClipData *curClip;
1370 if (op == Qt::IntersectClip)
1375 if (s->flags.has_clip_ownership) {
1379 newClip = new QClipData(d->rasterBuffer->height());
1381 s->flags.has_clip_ownership = true;
1384 QRegion r = s->matrix.map(region);
1385 if (curClip->hasRectClip)
1386 newClip->setClipRegion(r & curClip->clipRect);
1387 else if (curClip->hasRegionClip)
1388 newClip->setClipRegion(r & curClip->clipRegion);
1390 qrasterpaintengine_dirty_clip(d, s);
1397 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1399 #ifdef QT_DEBUG_DRAW
1400 qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1403 if (!fillData->blend)
1406 Q_D(QRasterPaintEngine);
1408 const QRectF controlPointRect = path.controlPointRect();
1410 QRasterPaintEngineState *s = state();
1411 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1412 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1413 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1414 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1415 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1416 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1418 if (!s->flags.antialiased && !do_clip) {
1419 d->initializeRasterizer(fillData);
1420 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1424 ensureOutlineMapper();
1425 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1428 static void fillRect_normalized(const QRect &r, QSpanData *data,
1429 QRasterPaintEnginePrivate *pe)
1433 bool rectClipped = true;
1436 x1 = qMax(r.x(), data->clip->xmin);
1437 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1438 y1 = qMax(r.y(), data->clip->ymin);
1439 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1440 rectClipped = data->clip->hasRectClip;
1443 x1 = qMax(r.x(), pe->deviceRect.x());
1444 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1445 y1 = qMax(r.y(), pe->deviceRect.y());
1446 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1448 x1 = qMax(r.x(), 0);
1449 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1450 y1 = qMax(r.y(), 0);
1451 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1454 if (x2 <= x1 || y2 <= y1)
1457 const int width = x2 - x1;
1458 const int height = y2 - y1;
1460 bool isUnclipped = rectClipped
1461 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1463 if (pe && isUnclipped) {
1464 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1466 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1467 || (mode == QPainter::CompositionMode_SourceOver
1468 && qAlpha(data->solid.color) == 255)))
1470 data->fillRect(data->rasterBuffer, x1, y1, width, height,
1476 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1478 const int nspans = 256;
1479 QT_FT_Span spans[nspans];
1481 Q_ASSERT(data->blend);
1484 int n = qMin(nspans, y2 - y);
1488 spans[i].len = width;
1490 spans[i].coverage = 255;
1494 blend(n, spans, data);
1502 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1504 #ifdef QT_DEBUG_DRAW
1505 qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1507 Q_D(QRasterPaintEngine);
1509 QRasterPaintEngineState *s = state();
1513 if (s->brushData.blend) {
1514 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1515 const QRect *r = rects;
1516 const QRect *lastRect = rects + rectCount;
1518 int offset_x = int(s->matrix.dx());
1519 int offset_y = int(s->matrix.dy());
1520 while (r < lastRect) {
1521 QRect rect = r->normalized();
1522 QRect rr = rect.translated(offset_x, offset_y);
1523 fillRect_normalized(rr, &s->brushData, d);
1527 QRectVectorPath path;
1528 for (int i=0; i<rectCount; ++i) {
1530 fill(path, s->brush);
1536 if (s->penData.blend) {
1537 QRectVectorPath path;
1538 if (s->flags.fast_pen) {
1539 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1540 for (int i = 0; i < rectCount; ++i) {
1542 stroker.drawPath(path);
1545 for (int i = 0; i < rectCount; ++i) {
1547 stroke(path, s->pen);
1556 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1558 #ifdef QT_DEBUG_DRAW
1559 qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1561 #ifdef QT_FAST_SPANS
1562 Q_D(QRasterPaintEngine);
1564 QRasterPaintEngineState *s = state();
1567 if (s->flags.tx_noshear) {
1569 if (s->brushData.blend) {
1570 d->initializeRasterizer(&s->brushData);
1571 for (int i = 0; i < rectCount; ++i) {
1572 const QRectF &rect = rects[i].normalized();
1575 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1576 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1577 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1582 if (s->penData.blend) {
1583 QRectVectorPath path;
1584 if (s->flags.fast_pen) {
1585 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1586 for (int i = 0; i < rectCount; ++i) {
1588 stroker.drawPath(path);
1591 for (int i = 0; i < rectCount; ++i) {
1593 QPaintEngineEx::stroke(path, s->lastPen);
1600 #endif // QT_FAST_SPANS
1601 QPaintEngineEx::drawRects(rects, rectCount);
1608 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1610 Q_D(QRasterPaintEngine);
1611 QRasterPaintEngineState *s = state();
1614 if (!s->penData.blend)
1617 if (s->flags.fast_pen) {
1618 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1619 stroker.drawPath(path);
1620 } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1621 qreal width = s->lastPen.isCosmetic()
1622 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1623 : qpen_widthf(s->lastPen) * s->txscale;
1625 qreal dashOffset = s->lastPen.dashOffset();
1627 qreal patternLength = 0;
1628 const QVector<qreal> pattern = s->lastPen.dashPattern();
1629 for (int i = 0; i < pattern.size(); ++i)
1630 patternLength += pattern.at(i);
1632 if (patternLength > 0) {
1633 int n = qFloor(dashOffset / patternLength);
1634 dashOffset -= n * patternLength;
1635 while (dashOffset >= pattern.at(dashIndex)) {
1636 dashOffset -= pattern.at(dashIndex);
1637 if (++dashIndex >= pattern.size())
1643 Q_D(QRasterPaintEngine);
1644 d->initializeRasterizer(&s->penData);
1645 int lineCount = path.elementCount() / 2;
1646 const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1648 for (int i = 0; i < lineCount; ++i) {
1649 if (lines[i].p1() == lines[i].p2()) {
1650 if (s->lastPen.capStyle() != Qt::FlatCap) {
1651 QPointF p = lines[i].p1();
1652 QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*qreal(0.5), p.y()),
1653 QPointF(p.x() + width*qreal(0.5), p.y())));
1654 d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1659 const QLineF line = s->matrix.map(lines[i]);
1660 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1661 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1662 width / line.length(),
1663 s->lastPen.capStyle() == Qt::SquareCap);
1665 d->rasterizeLine_dashed(line, width,
1666 &dashIndex, &dashOffset, &inDash);
1671 QPaintEngineEx::stroke(path, pen);
1674 static inline QRect toNormalizedFillRect(const QRectF &rect)
1676 int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1677 int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1678 int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1679 int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1686 return QRect(x1, y1, x2 - x1, y2 - y1);
1692 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1696 #ifdef QT_DEBUG_DRAW
1697 QRectF rf = path.controlPointRect();
1698 qDebug() << "QRasterPaintEngine::fill(): "
1699 << "size=" << path.elementCount()
1700 << ", hints=" << hex << path.hints()
1704 Q_D(QRasterPaintEngine);
1705 QRasterPaintEngineState *s = state();
1708 if (!s->brushData.blend)
1711 if (path.shape() == QVectorPath::RectangleHint) {
1712 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1713 const qreal *p = path.points();
1714 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1715 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1716 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1720 if (s->flags.tx_noshear) {
1721 d->initializeRasterizer(&s->brushData);
1722 // ### Is normalizing really necessary here?
1723 const qreal *p = path.points();
1724 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1726 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1727 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1728 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1734 // ### Optimize for non transformed ellipses and rectangles...
1735 QRectF cpRect = path.controlPointRect();
1736 const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1737 ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1740 // const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1741 // || deviceRect.right() > QT_RASTER_COORD_LIMIT
1742 // || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1743 // || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1745 // ### Falonc: implement....
1746 // if (!s->flags.antialiased && !do_clip) {
1747 // d->initializeRasterizer(&s->brushData);
1748 // d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1752 ensureOutlineMapper();
1753 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1756 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1758 Q_D(QRasterPaintEngine);
1759 QRasterPaintEngineState *s = state();
1761 if (!s->flags.antialiased) {
1762 uint txop = s->matrix.type();
1763 if (txop == QTransform::TxNone) {
1764 fillRect_normalized(toNormalizedFillRect(r), data, d);
1766 } else if (txop == QTransform::TxTranslate) {
1767 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1768 fillRect_normalized(rr, data, d);
1770 } else if (txop == QTransform::TxScale) {
1771 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1772 fillRect_normalized(rr, data, d);
1777 if (s->flags.tx_noshear) {
1778 d->initializeRasterizer(data);
1779 QRectF nr = r.normalized();
1780 if (!nr.isEmpty()) {
1781 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1782 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1783 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1790 ensureOutlineMapper();
1791 fillPath(path, data);
1797 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1799 #ifdef QT_DEBUG_DRAW
1800 qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1802 QRasterPaintEngineState *s = state();
1805 if (!s->brushData.blend)
1808 fillRect(r, &s->brushData);
1814 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1816 #ifdef QT_DEBUG_DRAW
1817 qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1819 Q_D(QRasterPaintEngine);
1820 QRasterPaintEngineState *s = state();
1822 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1823 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1824 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1827 d->solid_color_filler.clip = d->clip();
1828 d->solid_color_filler.adjustSpanMethods();
1829 fillRect(r, &d->solid_color_filler);
1832 static inline bool isAbove(const QPointF *a, const QPointF *b)
1834 return a->y() < b->y();
1837 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1842 Q_ASSERT(pointCount >= 2);
1844 QVector<const QPointF *> sorted;
1845 sorted.reserve(pointCount);
1847 upper->reserve(pointCount * 3 / 4);
1848 lower->reserve(pointCount * 3 / 4);
1850 for (int i = 0; i < pointCount; ++i)
1851 sorted << points + i;
1853 qSort(sorted.begin(), sorted.end(), isAbove);
1855 qreal splitY = sorted.at(sorted.size() / 2)->y();
1857 const QPointF *end = points + pointCount;
1858 const QPointF *last = end - 1;
1860 QVector<QPointF> *bin[2] = { upper, lower };
1862 for (const QPointF *p = points; p < end; ++p) {
1863 int side = p->y() < splitY;
1864 int lastSide = last->y() < splitY;
1866 if (side != lastSide) {
1867 if (qFuzzyCompare(p->y(), splitY)) {
1868 bin[!side]->append(*p);
1869 } else if (qFuzzyCompare(last->y(), splitY)) {
1870 bin[side]->append(*last);
1872 QPointF delta = *p - *last;
1873 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1875 bin[0]->append(intersection);
1876 bin[1]->append(intersection);
1880 bin[side]->append(*p);
1885 // give up if we couldn't reduce the point count
1886 return upper->size() < pointCount && lower->size() < pointCount;
1892 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1894 Q_D(QRasterPaintEngine);
1895 QRasterPaintEngineState *s = state();
1897 const int maxPoints = 0xffff;
1899 // max amount of points that raster engine can reliably handle
1900 if (pointCount > maxPoints) {
1901 QVector<QPointF> upper, lower;
1903 if (splitPolygon(points, pointCount, &upper, &lower)) {
1904 fillPolygon(upper.constData(), upper.size(), mode);
1905 fillPolygon(lower.constData(), lower.size(), mode);
1907 qWarning("Polygon too complex for filling.");
1912 // Compose polygon fill..,
1913 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1914 ensureOutlineMapper();
1915 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1918 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1920 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1926 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1928 Q_D(QRasterPaintEngine);
1929 QRasterPaintEngineState *s = state();
1931 #ifdef QT_DEBUG_DRAW
1932 qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1933 for (int i=0; i<pointCount; ++i)
1934 qDebug() << " - " << points[i];
1936 Q_ASSERT(pointCount >= 2);
1938 if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1939 QRectF r(points[0], points[2]);
1945 if (mode != PolylineMode) {
1948 if (s->brushData.blend)
1949 fillPolygon(points, pointCount, mode);
1952 // Do the outline...
1953 if (s->penData.blend) {
1954 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1955 if (s->flags.fast_pen) {
1956 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1957 stroker.drawPath(vp);
1959 QPaintEngineEx::stroke(vp, s->lastPen);
1967 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1969 Q_D(QRasterPaintEngine);
1970 QRasterPaintEngineState *s = state();
1972 #ifdef QT_DEBUG_DRAW
1973 qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1974 for (int i=0; i<pointCount; ++i)
1975 qDebug() << " - " << points[i];
1977 Q_ASSERT(pointCount >= 2);
1978 if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1979 QRect r(points[0].x(),
1981 points[2].x() - points[0].x(),
1982 points[2].y() - points[0].y());
1990 if (mode != PolylineMode) {
1992 if (s->brushData.blend) {
1993 // Compose polygon fill..,
1994 ensureOutlineMapper();
1995 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1996 d->outlineMapper->moveTo(*points);
1997 const QPoint *p = points;
1998 const QPoint *ep = points + pointCount - 1;
2000 d->outlineMapper->lineTo(*(++p));
2002 d->outlineMapper->endOutline();
2005 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2007 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2011 // Do the outline...
2012 if (s->penData.blend) {
2013 int count = pointCount * 2;
2014 QVarLengthArray<qreal> fpoints(count);
2016 for (int i=0; i<count; i+=2) {
2017 fpoints[i] = ((int *) points)[i+1];
2018 fpoints[i+1] = ((int *) points)[i];
2021 for (int i=0; i<count; ++i)
2022 fpoints[i] = ((int *) points)[i];
2024 QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2026 if (s->flags.fast_pen) {
2027 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
2028 stroker.drawPath(vp);
2030 QPaintEngineEx::stroke(vp, s->lastPen);
2038 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2040 #ifdef QT_DEBUG_DRAW
2041 qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2044 QPixmapData *pd = pixmap.pixmapData();
2045 if (pd->classId() == QPixmapData::RasterClass) {
2046 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2047 if (image.depth() == 1) {
2048 Q_D(QRasterPaintEngine);
2049 QRasterPaintEngineState *s = state();
2050 if (s->matrix.type() <= QTransform::TxTranslate) {
2052 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2054 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2057 QRasterPaintEngine::drawImage(pos, image);
2060 const QImage image = pixmap.toImage();
2061 if (pixmap.depth() == 1) {
2062 Q_D(QRasterPaintEngine);
2063 QRasterPaintEngineState *s = state();
2064 if (s->matrix.type() <= QTransform::TxTranslate) {
2066 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2068 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2071 QRasterPaintEngine::drawImage(pos, image);
2079 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2081 #ifdef QT_DEBUG_DRAW
2082 qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2085 QPixmapData* pd = pixmap.pixmapData();
2086 if (pd->classId() == QPixmapData::RasterClass) {
2087 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2088 if (image.depth() == 1) {
2089 Q_D(QRasterPaintEngine);
2090 QRasterPaintEngineState *s = state();
2091 if (s->matrix.type() <= QTransform::TxTranslate
2092 && r.size() == sr.size()
2093 && r.size() == pixmap.size()) {
2095 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2098 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2101 drawImage(r, image, sr);
2104 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2105 const QImage image = pd->toImage(clippedSource);
2106 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2107 if (image.depth() == 1) {
2108 Q_D(QRasterPaintEngine);
2109 QRasterPaintEngineState *s = state();
2110 if (s->matrix.type() <= QTransform::TxTranslate
2111 && r.size() == sr.size()
2112 && r.size() == pixmap.size()) {
2114 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2117 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2120 drawImage(r, image, translatedSource);
2125 // assumes that rect has positive width and height
2126 static inline const QRect toRect_normalized(const QRectF &rect)
2128 const int x = qRound(rect.x());
2129 const int y = qRound(rect.y());
2130 const int w = int(rect.width() + qreal(0.5));
2131 const int h = int(rect.height() + qreal(0.5));
2133 return QRect(x, y, w, h);
2136 static inline int fast_ceil_positive(const qreal &v)
2138 const int iv = int(v);
2145 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2147 const int xmin = int(rect.x());
2148 const int xmax = int(fast_ceil_positive(rect.right()));
2149 const int ymin = int(rect.y());
2150 const int ymax = int(fast_ceil_positive(rect.bottom()));
2151 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2157 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2159 #ifdef QT_DEBUG_DRAW
2160 qDebug() << " - QRasterPaintEngine::drawImage(), p=" << p << " image=" << img.size() << "depth=" << img.depth();
2163 Q_D(QRasterPaintEngine);
2164 QRasterPaintEngineState *s = state();
2166 if (s->matrix.type() > QTransform::TxTranslate) {
2167 drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2169 QRectF(0, 0, img.width(), img.height()));
2172 const QClipData *clip = d->clip();
2173 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2175 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2176 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2179 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2181 } else if (clip->hasRectClip) {
2182 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2190 d->image_filler.clip = clip;
2191 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2192 if (!d->image_filler.blend)
2194 d->image_filler.dx = -pt.x();
2195 d->image_filler.dy = -pt.y();
2196 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2198 fillRect_normalized(rr, &d->image_filler, d);
2203 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2205 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2216 inline RotationType qRotationType(const QTransform &transform)
2218 QTransform::TransformationType type = transform.type();
2220 if (type > QTransform::TxRotate)
2223 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2224 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2227 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2228 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2231 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2232 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2238 inline bool isPixelAligned(const QRectF &rect) {
2239 return QRectF(rect.toRect()) == rect;
2246 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2247 Qt::ImageConversionFlags)
2249 #ifdef QT_DEBUG_DRAW
2250 qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2256 Q_D(QRasterPaintEngine);
2257 QRasterPaintEngineState *s = state();
2258 int sr_l = qFloor(sr.left());
2259 int sr_r = qCeil(sr.right()) - 1;
2260 int sr_t = qFloor(sr.top());
2261 int sr_b = qCeil(sr.bottom()) - 1;
2263 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2264 // as fillRect will apply the aliased coordinate delta we need to
2265 // subtract it here as we don't use it for image drawing
2266 QTransform old = s->matrix;
2267 s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2269 // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2270 QRgb color = img.pixel(sr_l, sr_t);
2271 switch (img.format()) {
2272 case QImage::Format_ARGB32_Premultiplied:
2273 case QImage::Format_ARGB8565_Premultiplied:
2274 case QImage::Format_ARGB6666_Premultiplied:
2275 case QImage::Format_ARGB8555_Premultiplied:
2276 case QImage::Format_ARGB4444_Premultiplied:
2277 // Combine premultiplied color with the opacity set on the painter.
2278 d->solid_color_filler.solid.color =
2279 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2280 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2283 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2287 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2288 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2292 d->solid_color_filler.clip = d->clip();
2293 d->solid_color_filler.adjustSpanMethods();
2294 fillRect(r, &d->solid_color_filler);
2300 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2302 const QClipData *clip = d->clip();
2304 if (s->matrix.type() > QTransform::TxTranslate
2306 && (!clip || clip->hasRectClip)
2307 && s->intOpacity == 256
2308 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2309 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2310 && d->rasterBuffer->format == img.format()
2311 && (d->rasterBuffer->format == QImage::Format_RGB16
2312 || d->rasterBuffer->format == QImage::Format_RGB32
2313 || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2314 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2316 RotationType rotationType = qRotationType(s->matrix);
2318 if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2319 QRectF transformedTargetRect = s->matrix.mapRect(r);
2321 if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2322 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2324 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2325 if (clippedTransformedTargetRect.isNull())
2328 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2330 QRect clippedSourceRect
2331 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2332 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2334 uint dbpl = d->rasterBuffer->bytesPerLine();
2335 uint sbpl = img.bytesPerLine();
2337 uchar *dst = d->rasterBuffer->buffer();
2338 uint bpp = img.depth() >> 3;
2340 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2341 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2343 uint cw = clippedSourceRect.width();
2344 uint ch = clippedSourceRect.height();
2346 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2353 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2355 QRectF targetBounds = s->matrix.mapRect(r);
2356 bool exceedsPrecision = targetBounds.width() > 0xffff
2357 || targetBounds.height() > 0xffff;
2359 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2360 if (s->matrix.type() > QTransform::TxScale) {
2361 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2362 if (func && (!clip || clip->hasRectClip)) {
2363 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2364 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2365 s->matrix, s->intOpacity);
2369 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2370 if (func && (!clip || clip->hasRectClip)) {
2371 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2372 img.bits(), img.bytesPerLine(), img.height(),
2373 qt_mapRect_non_normalizing(r, s->matrix), sr,
2374 !clip ? d->deviceRect : clip->clipRect,
2381 QTransform copy = s->matrix;
2382 copy.translate(r.x(), r.y());
2384 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2385 copy.translate(-sr.x(), -sr.y());
2387 d->image_filler_xform.clip = clip;
2388 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2389 if (!d->image_filler_xform.blend)
2391 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2393 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2394 QPointF rr_tl = s->matrix.map(r.topLeft());
2395 QPointF rr_br = s->matrix.map(r.bottomRight());
2397 int x1 = qRound(rr_tl.x());
2398 int y1 = qRound(rr_tl.y());
2399 int x2 = qRound(rr_br.x());
2400 int y2 = qRound(rr_br.y());
2407 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2411 #ifdef QT_FAST_SPANS
2413 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2414 d->initializeRasterizer(&d->image_filler_xform);
2415 d->rasterizer->setAntialiased(s->flags.antialiased);
2417 const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2419 const QRectF &rect = r.normalized();
2420 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2421 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2423 if (s->flags.tx_noshear)
2424 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2426 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2430 const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2433 QTransform m = s->matrix;
2434 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2435 m.m21(), m.m22(), m.m23(),
2436 m.m31() - offs, m.m32() - offs, m.m33());
2437 fillPath(path, &d->image_filler_xform);
2440 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2441 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2443 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2445 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2447 } else if (clip->hasRectClip) {
2448 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2454 d->image_filler.clip = clip;
2455 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2456 if (!d->image_filler.blend)
2458 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2459 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2462 rr.translate(s->matrix.dx(), s->matrix.dy());
2464 const int x1 = qRound(rr.x());
2465 const int y1 = qRound(rr.y());
2466 const int x2 = qRound(rr.right());
2467 const int y2 = qRound(rr.bottom());
2469 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2476 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2478 #ifdef QT_DEBUG_DRAW
2479 qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2481 Q_D(QRasterPaintEngine);
2482 QRasterPaintEngineState *s = state();
2486 QPixmapData *pd = pixmap.pixmapData();
2487 if (pd->classId() == QPixmapData::RasterClass) {
2488 image = static_cast<QRasterPixmapData *>(pd)->image;
2490 image = pixmap.toImage();
2493 if (image.depth() == 1)
2494 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2496 if (s->matrix.type() > QTransform::TxTranslate) {
2497 QTransform copy = s->matrix;
2498 copy.translate(r.x(), r.y());
2499 copy.translate(-sr.x(), -sr.y());
2500 d->image_filler_xform.clip = d->clip();
2501 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2502 if (!d->image_filler_xform.blend)
2504 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2506 #ifdef QT_FAST_SPANS
2508 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2509 d->initializeRasterizer(&d->image_filler_xform);
2510 d->rasterizer->setAntialiased(s->flags.antialiased);
2512 const QRectF &rect = r.normalized();
2513 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2514 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2515 if (s->flags.tx_noshear)
2516 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2518 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2524 fillPath(path, &d->image_filler_xform);
2526 d->image_filler.clip = d->clip();
2528 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2529 if (!d->image_filler.blend)
2531 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2532 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2535 rr.translate(s->matrix.dx(), s->matrix.dy());
2536 fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2542 static inline bool monoVal(const uchar* s, int x)
2544 return (s[x>>3] << (x&7)) & 0x80;
2550 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2552 Q_D(QRasterPaintEngine);
2553 QRasterPaintEngineState *s = state();
2555 if (!s->penData.blend)
2558 QRasterBuffer *rb = d->rasterBuffer.data();
2560 const QRect rect(rx, ry, w, h);
2561 const QClipData *clip = d->clip();
2562 bool unclipped = false;
2564 // inlined QRect::intersects
2565 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2566 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2568 if (clip->hasRectClip) {
2569 unclipped = rx > clip->xmin
2570 && rx + w < clip->xmax
2572 && ry + h < clip->ymax;
2578 // inlined QRect::intersects
2579 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2580 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2584 // inlined QRect::contains
2585 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2586 && rect.top() >= 0 && rect.bottom() < rb->height();
2588 unclipped = contains && d->isUnclipped_normalized(rect);
2591 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2592 const uchar * scanline = static_cast<const uchar *>(src);
2594 if (s->flags.fast_text) {
2597 if (s->penData.bitmapBlit) {
2598 s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2599 scanline, w, h, bpl);
2602 } else if (depth == 8) {
2603 if (s->penData.alphamapBlit) {
2604 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2605 scanline, w, h, bpl, 0);
2608 } else if (depth == 32) {
2609 // (A)RGB Alpha mask where the alpha component is not used.
2610 if (s->penData.alphaRGBBlit) {
2611 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2612 (const uint *) scanline, w, h, bpl / 4, 0);
2616 } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2617 // (A)RGB Alpha mask where the alpha component is not used.
2619 int nx = qMax(0, rx);
2620 int ny = qMax(0, ry);
2622 // Move scanline pointer to compensate for moved x and y
2623 int xdiff = nx - rx;
2624 int ydiff = ny - ry;
2625 scanline += ydiff * bpl;
2626 scanline += xdiff * (depth == 32 ? 4 : 1);
2631 if (nx + w > d->rasterBuffer->width())
2632 w = d->rasterBuffer->width() - nx;
2633 if (ny + h > d->rasterBuffer->height())
2634 h = d->rasterBuffer->height() - ny;
2639 if (depth == 8 && s->penData.alphamapBlit) {
2640 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2641 scanline, w, h, bpl, clip);
2642 } else if (depth == 32 && s->penData.alphaRGBBlit) {
2643 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2644 (const uint *) scanline, w, h, bpl / 4, clip);
2659 scanline += bpl * y0;
2663 w = qMin(w, rb->width() - qMax(0, rx));
2664 h = qMin(h, rb->height() - qMax(0, ry));
2666 if (w <= 0 || h <= 0)
2669 const int NSPANS = 256;
2670 QSpan spans[NSPANS];
2673 const int x1 = x0 + w;
2674 const int y1 = y0 + h;
2677 for (int y = y0; y < y1; ++y) {
2678 for (int x = x0; x < x1; ) {
2679 if (!monoVal(scanline, x)) {
2684 if (current == NSPANS) {
2685 blend(current, spans, &s->penData);
2688 spans[current].x = x + rx;
2689 spans[current].y = y + ry;
2690 spans[current].coverage = 255;
2693 // extend span until we find a different one.
2694 while (x < x1 && monoVal(scanline, x)) {
2698 spans[current].len = len;
2703 } else if (depth == 8) {
2704 for (int y = y0; y < y1; ++y) {
2705 for (int x = x0; x < x1; ) {
2706 // Skip those with 0 coverage
2707 if (scanline[x] == 0) {
2712 if (current == NSPANS) {
2713 blend(current, spans, &s->penData);
2716 int coverage = scanline[x];
2717 spans[current].x = x + rx;
2718 spans[current].y = y + ry;
2719 spans[current].coverage = coverage;
2723 // extend span until we find a different one.
2724 while (x < x1 && scanline[x] == coverage) {
2728 spans[current].len = len;
2733 } else { // 32-bit alpha...
2734 uint *sl = (uint *) src;
2735 for (int y = y0; y < y1; ++y) {
2736 for (int x = x0; x < x1; ) {
2737 // Skip those with 0 coverage
2738 if ((sl[x] & 0x00ffffff) == 0) {
2743 if (current == NSPANS) {
2744 blend(current, spans, &s->penData);
2747 uint rgbCoverage = sl[x];
2748 int coverage = qGreen(rgbCoverage);
2749 spans[current].x = x + rx;
2750 spans[current].y = y + ry;
2751 spans[current].coverage = coverage;
2755 // extend span until we find a different one.
2756 while (x < x1 && sl[x] == rgbCoverage) {
2760 spans[current].len = len;
2763 sl += bpl / sizeof(uint);
2766 // qDebug() << "alphaPenBlt: num spans=" << current
2767 // << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2768 // Call span func for current set of spans.
2770 blend(current, spans, &s->penData);
2773 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2774 const QFixedPoint *positions, QFontEngine *fontEngine)
2776 Q_D(QRasterPaintEngine);
2777 QRasterPaintEngineState *s = state();
2778 const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2780 #if !defined(QT_NO_FREETYPE)
2781 if (fontEngine->type() == QFontEngine::Freetype) {
2782 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2783 const QFixed xOffs = fe->supportsSubPixelPositions() ? 0 : offs;
2784 QFontEngineFT::GlyphFormat neededFormat =
2785 painter()->device()->devType() == QInternal::Widget
2786 ? fe->defaultGlyphFormat()
2787 : QFontEngineFT::Format_A8;
2789 if (d_func()->mono_surface
2790 || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2792 neededFormat = QFontEngineFT::Format_Mono;
2794 if (neededFormat == QFontEngineFT::Format_None)
2795 neededFormat = QFontEngineFT::Format_A8;
2797 QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2798 if (s->matrix.type() >= QTransform::TxScale) {
2799 if (s->matrix.isAffine())
2800 gset = fe->loadTransformedGlyphSet(s->matrix);
2805 if (!gset || gset->outline_drawing
2806 || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2809 FT_Face lockedFace = 0;
2812 switch (neededFormat) {
2813 case QFontEngineFT::Format_Mono:
2816 case QFontEngineFT::Format_A8:
2819 case QFontEngineFT::Format_A32:
2827 for (int i = 0; i < numGlyphs; i++) {
2828 QFixed spp = fe->subPixelPositionForX(positions[i].x);
2829 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2831 if (!glyph || glyph->format != neededFormat) {
2833 lockedFace = fe->lockFace();
2834 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2837 if (!glyph || !glyph->data)
2841 switch (neededFormat) {
2842 case QFontEngineFT::Format_Mono:
2843 pitch = ((glyph->width + 31) & ~31) >> 3;
2845 case QFontEngineFT::Format_A8:
2846 pitch = (glyph->width + 3) & ~3;
2848 case QFontEngineFT::Format_A32:
2849 pitch = glyph->width * 4;
2856 alphaPenBlt(glyph->data, pitch, depth,
2857 qFloor(positions[i].x + xOffs) + glyph->x,
2858 qFloor(positions[i].y + offs) - glyph->y,
2859 glyph->width, glyph->height);
2866 QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0
2867 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat)
2868 : d->glyphCacheType;
2870 QImageTextureGlyphCache *cache =
2871 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2873 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2874 fontEngine->setGlyphCache(0, cache);
2877 cache->populate(fontEngine, numGlyphs, glyphs, positions);
2878 cache->fillInPendingGlyphs();
2880 const QImage &image = cache->image();
2881 int bpl = image.bytesPerLine();
2883 int depth = image.depth();
2887 leftShift = 2; // multiply by 4
2888 else if (depth == 1)
2889 rightShift = 3; // divide by 8
2891 int margin = cache->glyphMargin();
2892 const uchar *bits = image.bits();
2893 for (int i=0; i<numGlyphs; ++i) {
2895 QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2896 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2897 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2901 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2902 int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2904 // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2907 // c.baseLineX, c.baseLineY,
2910 // positions[i].x.toInt(), positions[i].y.toInt());
2912 alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2918 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2919 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2921 Q_D(QRasterPaintEngine);
2922 QRasterPaintEngineState *s = state();
2924 QFontEngine *fontEngine = ti.fontEngine;
2925 if (fontEngine->type() != QFontEngine::S60FontEngine) {
2926 QPaintEngineEx::drawTextItem(p, ti);
2930 QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2932 QVarLengthArray<QFixedPoint> positions;
2933 QVarLengthArray<glyph_t> glyphs;
2934 QTransform matrix = s->matrix;
2935 matrix.translate(p.x(), p.y());
2936 if (matrix.type() == QTransform::TxScale)
2937 fe->setFontScale(matrix.m11());
2938 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2940 const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2942 for (int i=0; i<glyphs.size(); ++i) {
2943 TOpenFontCharMetrics tmetrics;
2944 const TUint8 *glyphBitmapBytes;
2945 TSize glyphBitmapSize;
2946 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2947 const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
2948 const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
2949 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2952 if (matrix.type() == QTransform::TxScale)
2953 fe->setFontScale(1.0);
2957 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2960 * Returns true if the rectangle is completely within the current clip
2961 * state of the paint engine.
2963 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2965 const QClipData *cl = clip();
2967 // inline contains() for performance (we know the rects are normalized)
2968 const QRect &r1 = deviceRect;
2969 return (r.left() >= r1.left() && r.right() <= r1.right()
2970 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2974 if (cl->hasRectClip) {
2975 // currently all painting functions clips to deviceRect internally
2976 if (cl->clipRect == deviceRect)
2979 // inline contains() for performance (we know the rects are normalized)
2980 const QRect &r1 = cl->clipRect;
2981 return (r.left() >= r1.left() && r.right() <= r1.right()
2982 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2984 return qt_region_strictContains(cl->clipRegion, r);
2988 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2991 Q_Q(const QRasterPaintEngine);
2992 const QRasterPaintEngineState *s = q->state();
2993 const QClipData *cl = clip();
2995 QRect r = rect.normalized();
2996 // inline contains() for performance (we know the rects are normalized)
2997 const QRect &r1 = deviceRect;
2998 return (r.left() >= r1.left() && r.right() <= r1.right()
2999 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3003 // currently all painting functions that call this function clip to deviceRect internally
3004 if (cl->hasRectClip && cl->clipRect == deviceRect)
3007 if (s->flags.antialiased)
3010 QRect r = rect.normalized();
3012 r.setX(r.x() - penWidth);
3013 r.setY(r.y() - penWidth);
3014 r.setWidth(r.width() + 2 * penWidth);
3015 r.setHeight(r.height() + 2 * penWidth);
3018 if (cl->hasRectClip) {
3019 // inline contains() for performance (we know the rects are normalized)
3020 const QRect &r1 = cl->clipRect;
3021 return (r.left() >= r1.left() && r.right() <= r1.right()
3022 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3024 return qt_region_strictContains(cl->clipRegion, r);
3028 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3031 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3035 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3036 const QSpanData *data) const
3038 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3042 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3043 const QSpanData *data) const
3045 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3049 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
3050 const QSpanData *data) const
3052 Q_Q(const QRasterPaintEngine);
3053 const QRasterPaintEngineState *s = q->state();
3055 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3057 const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
3058 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3064 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3069 QFontEngine *fontEngine = textItem->fontEngine();
3070 if (!supportsTransformations(fontEngine)) {
3071 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3074 QPaintEngineEx::drawStaticTextItem(textItem);
3081 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3083 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3084 QRasterPaintEngineState *s = state();
3086 #ifdef QT_DEBUG_DRAW
3087 Q_D(QRasterPaintEngine);
3088 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3089 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3096 #if defined (Q_WS_WIN) || defined(Q_WS_MAC) || (defined(Q_OS_MAC) && defined(Q_WS_QPA))
3098 if (!supportsTransformations(ti.fontEngine)) {
3099 QVarLengthArray<QFixedPoint> positions;
3100 QVarLengthArray<glyph_t> glyphs;
3102 QTransform matrix = s->matrix;
3103 matrix.translate(p.x(), p.y());
3105 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3107 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3111 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3112 if (s->matrix.type() <= QTransform::TxTranslate
3113 || (s->matrix.type() == QTransform::TxScale
3114 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3115 drawGlyphsS60(p, ti);
3118 #else // Q_WS_WIN || Q_WS_MAC
3120 QFontEngine *fontEngine = ti.fontEngine;
3122 #if defined(Q_WS_QWS)
3123 if (fontEngine->type() == QFontEngine::Box) {
3124 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3128 if (s->matrix.type() < QTransform::TxScale
3129 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3130 || (fontEngine->type() == QFontEngine::Proxy
3131 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3133 fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3139 if (s->matrix.type() < QTransform::TxScale) {
3141 QVarLengthArray<QFixedPoint> positions;
3142 QVarLengthArray<glyph_t> glyphs;
3143 QTransform matrix = state()->transform();
3145 qreal _x = qFloor(p.x());
3146 qreal _y = qFloor(p.y());
3147 matrix.translate(_x, _y);
3149 fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3150 if (glyphs.size() == 0)
3153 for(int i = 0; i < glyphs.size(); i++) {
3154 QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3155 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3156 // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3157 alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3158 qRound(positions[i].x + metrics.x),
3159 qRound(positions[i].y + metrics.y),
3160 img.width(), img.height());
3166 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3168 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3169 if (fontEngine->type() == QFontEngine::QPF2) {
3170 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3171 if (renderingEngine)
3172 fontEngine = renderingEngine;
3176 if (fontEngine->type() != QFontEngine::Freetype) {
3177 QPaintEngineEx::drawTextItem(p, ti);
3181 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3183 QTransform matrix = s->matrix;
3184 matrix.translate(p.x(), p.y());
3186 QVarLengthArray<QFixedPoint> positions;
3187 QVarLengthArray<glyph_t> glyphs;
3188 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3189 if (glyphs.size() == 0)
3192 if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3193 QPaintEngine::drawTextItem(p, ti);
3199 QPaintEngineEx::drawTextItem(p, ti);
3205 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3207 Q_D(QRasterPaintEngine);
3208 QRasterPaintEngineState *s = state();
3211 if (!s->penData.blend)
3214 if (!s->flags.fast_pen) {
3215 QPaintEngineEx::drawPoints(points, pointCount);
3219 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3220 stroker.drawPoints(points, pointCount);
3224 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3226 Q_D(QRasterPaintEngine);
3227 QRasterPaintEngineState *s = state();
3230 if (!s->penData.blend)
3233 if (!s->flags.fast_pen) {
3234 QPaintEngineEx::drawPoints(points, pointCount);
3238 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3239 stroker.drawPoints(points, pointCount);
3245 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3247 #ifdef QT_DEBUG_DRAW
3248 qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3250 Q_D(QRasterPaintEngine);
3251 QRasterPaintEngineState *s = state();
3254 if (!s->penData.blend)
3257 if (s->flags.fast_pen) {
3258 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3259 for (int i=0; i<lineCount; ++i) {
3260 const QLine &l = lines[i];
3261 stroker.drawLine(l.p1(), l.p2());
3264 QPaintEngineEx::drawLines(lines, lineCount);
3268 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3274 Q_Q(QRasterPaintEngine);
3275 QRasterPaintEngineState *s = q->state();
3277 const QPen &pen = s->lastPen;
3278 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3279 const QVector<qreal> pattern = pen.dashPattern();
3281 qreal patternLength = 0;
3282 for (int i = 0; i < pattern.size(); ++i)
3283 patternLength += pattern.at(i);
3285 if (patternLength <= 0)
3288 qreal length = line.length();
3289 Q_ASSERT(length > 0);
3290 while (length > 0) {
3291 const bool rasterize = *inDash;
3292 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3295 if (dash >= length) {
3297 *dashOffset += dash / width;
3301 *inDash = !(*inDash);
3302 if (++*dashIndex >= pattern.size())
3309 if (rasterize && dash > 0)
3310 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3317 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3319 #ifdef QT_DEBUG_DRAW
3320 qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3322 Q_D(QRasterPaintEngine);
3323 QRasterPaintEngineState *s = state();
3326 if (!s->penData.blend)
3328 if (s->flags.fast_pen) {
3329 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3330 for (int i=0; i<lineCount; ++i) {
3331 QLineF line = lines[i];
3332 stroker.drawLine(line.p1(), line.p2());
3335 QPaintEngineEx::drawLines(lines, lineCount);
3343 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3345 Q_D(QRasterPaintEngine);
3346 QRasterPaintEngineState *s = state();
3349 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3350 || (qpen_style(s->lastPen) == Qt::NoPen))
3351 && !s->flags.antialiased
3352 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3354 && s->matrix.type() <= QTransform::TxScale) // no shear
3357 const QRectF r = s->matrix.mapRect(rect);
3358 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3359 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3360 const QRect brect = QRect(int(r.x()), int(r.y()),
3361 int_dim(r.x(), r.width()),
3362 int_dim(r.y(), r.height()));
3364 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3365 &s->penData, &s->brushData);
3369 QPaintEngineEx::drawEllipse(rect);
3376 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3378 Q_D(QRasterPaintEngine);
3385 CGContextRef QRasterPaintEngine::getCGContext() const
3387 Q_D(const QRasterPaintEngine);
3388 return d->cgContext;
3396 void QRasterPaintEngine::setDC(HDC hdc) {
3397 Q_D(QRasterPaintEngine);
3404 HDC QRasterPaintEngine::getDC() const
3406 Q_D(const QRasterPaintEngine);
3413 void QRasterPaintEngine::releaseDC(HDC) const
3419 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3423 const QTransform &m = state()->matrix;
3424 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3425 QFontEngine::Type fontEngineType = fontEngine->type();
3426 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3427 || (m.type() <= QTransform::TxTranslate
3428 && (fontEngineType == QFontEngine::TestFontEngine
3429 || fontEngineType == QFontEngine::Box))) {
3433 return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3436 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3438 #if defined(Q_WS_MAC) || (defined(Q_OS_MAC) && defined(Q_WS_QPA))
3439 // Mac font engines don't support scaling and rotation
3440 if (m.type() > QTransform::TxTranslate)
3442 if (m.type() >= QTransform::TxProject)
3446 if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 *&nbs