1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 struct QRasterFloatPoint {
169 static const QRectF boundingRect(const QPointF *points, int pointCount)
171 const QPointF *e = points;
172 const QPointF *last = points + pointCount;
173 qreal minx, maxx, miny, maxy;
174 minx = maxx = e->x();
175 miny = maxy = e->y();
179 else if (e->x() > maxx)
183 else if (e->y() > maxy)
186 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
190 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
191 return (elementCount == 5 // 5-point polygon, check for closed rect
192 && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
193 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
194 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
195 && pts[0] < pts[4] && pts[1] < pts[5]
197 (elementCount == 4 // 4-point polygon, check for unclosed rect
198 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
199 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
200 && pts[0] < pts[4] && pts[1] < pts[5]
205 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
207 ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
210 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
212 ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
215 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
216 qfixed c2x, qfixed c2y,
217 qfixed ex, qfixed ey,
220 ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
221 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
222 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
226 #if !defined(QT_NO_DEBUG) && 0
227 static void qt_debug_path(const QPainterPath &path)
229 const char *names[] = {
236 fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
237 for (int i=0; i<path.elementCount(); ++i) {
238 const QPainterPath::Element &e = path.elementAt(i);
239 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
240 fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
245 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
246 QPaintEngineExPrivate(),
253 \class QRasterPaintEngine
258 \brief The QRasterPaintEngine class enables hardware acceleration
259 of painting operations in Qt for Embedded Linux.
261 Note that this functionality is only available in
262 \l{Qt for Embedded Linux}.
264 In \l{Qt for Embedded Linux}, painting is a pure software
265 implementation. But starting with Qt 4.2, it is
266 possible to add an accelerated graphics driver to take advantage
267 of available hardware resources.
269 Hardware acceleration is accomplished by creating a custom screen
270 driver, accelerating the copying from memory to the screen, and
271 implementing a custom paint engine accelerating the various
272 painting operations. Then a custom paint device (derived from the
273 QCustomRasterPaintDevice class) and a custom window surface
274 (derived from QWSWindowSurface) must be implemented to make
275 \l{Qt for Embedded Linux} aware of the accelerated driver.
277 \note The QRasterPaintEngine class does not support 8-bit images.
278 Instead, they need to be converted to a supported format, such as
279 QImage::Format_ARGB32_Premultiplied.
281 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
282 documentation for details.
284 \sa QCustomRasterPaintDevice, QPaintEngine
288 \fn Type QRasterPaintEngine::type() const
294 \relates QRasterPaintEngine
296 A struct equivalent to QT_FT_Span, containing a position (x,
297 y), the span's length in pixels and its color/coverage (a value
298 ranging from 0 to 255).
304 Creates a raster based paint engine for operating on the given
305 \a device, with the complete set of \l
306 {QPaintEngine::PaintEngineFeature}{paint engine features and
309 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
310 : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
312 d_func()->device = device;
319 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
322 d_func()->device = device;
326 void QRasterPaintEngine::init()
328 Q_D(QRasterPaintEngine);
335 // The antialiasing raster.
336 d->grayRaster.reset(new QT_FT_Raster);
337 Q_CHECK_PTR(d->grayRaster.data());
338 if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
339 QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
342 d->rasterizer.reset(new QRasterizer);
343 d->rasterBuffer.reset(new QRasterBuffer());
344 d->outlineMapper.reset(new QOutlineMapper);
345 d->outlinemapper_xform_dirty = true;
347 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
348 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
349 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
351 d->baseClip.reset(new QClipData(d->device->height()));
352 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
354 d->image_filler.init(d->rasterBuffer.data(), this);
355 d->image_filler.type = QSpanData::Texture;
357 d->image_filler_xform.init(d->rasterBuffer.data(), this);
358 d->image_filler_xform.type = QSpanData::Texture;
360 d->solid_color_filler.init(d->rasterBuffer.data(), this);
361 d->solid_color_filler.type = QSpanData::Solid;
363 d->deviceDepth = d->device->depth();
365 d->mono_surface = false;
366 gccaps &= ~PorterDuff;
368 QImage::Format format = QImage::Format_Invalid;
370 switch (d->device->devType()) {
371 case QInternal::Pixmap:
372 qWarning("QRasterPaintEngine: unsupported for pixmaps...");
374 case QInternal::Image:
375 format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
378 case QInternal::CustomRaster:
379 d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
383 qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
389 case QImage::Format_MonoLSB:
390 case QImage::Format_Mono:
391 d->mono_surface = true;
393 case QImage::Format_ARGB8565_Premultiplied:
394 case QImage::Format_ARGB8555_Premultiplied:
395 case QImage::Format_ARGB6666_Premultiplied:
396 case QImage::Format_ARGB4444_Premultiplied:
397 case QImage::Format_ARGB32_Premultiplied:
398 case QImage::Format_ARGB32:
399 gccaps |= PorterDuff;
401 case QImage::Format_RGB32:
402 case QImage::Format_RGB444:
403 case QImage::Format_RGB555:
404 case QImage::Format_RGB666:
405 case QImage::Format_RGB888:
406 case QImage::Format_RGB16:
417 Destroys this paint engine.
419 QRasterPaintEngine::~QRasterPaintEngine()
421 Q_D(QRasterPaintEngine);
423 qt_ft_grays_raster.raster_done(*d->grayRaster.data());
429 bool QRasterPaintEngine::begin(QPaintDevice *device)
431 Q_D(QRasterPaintEngine);
433 if (device->devType() == QInternal::Pixmap) {
434 QPixmap *pixmap = static_cast<QPixmap *>(device);
435 QPixmapData *pd = pixmap->pixmapData();
436 if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
437 d->device = pd->buffer();
442 // Make sure QPaintEngine::paintDevice() returns the proper device.
445 Q_ASSERT(d->device->devType() == QInternal::Image
446 || d->device->devType() == QInternal::CustomRaster);
448 d->systemStateChanged();
450 QRasterPaintEngineState *s = state();
451 ensureOutlineMapper();
452 d->outlineMapper->m_clip_rect = d->deviceRect;
454 if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
455 d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
456 if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
457 d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
459 d->rasterizer->setClipRect(d->deviceRect);
461 s->penData.init(d->rasterBuffer.data(), this);
462 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
463 s->stroker = &d->basicStroker;
464 d->basicStroker.setClipRect(d->deviceRect);
466 s->brushData.init(d->rasterBuffer.data(), this);
467 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
469 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
471 setDirty(DirtyBrushOrigin);
474 qDebug() << "QRasterPaintEngine::begin(" << (void *) device
475 << ") devType:" << device->devType()
476 << "devRect:" << d->deviceRect;
478 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
482 #if defined(Q_WS_WIN)
483 d->isPlain45DegreeRotation = true;
487 d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
488 #if defined(Q_WS_WIN)
489 else if (qt_cleartype_enabled)
490 #elif defined (Q_WS_MAC)
491 else if (qt_applefontsmoothing_enabled)
496 QImage::Format format = static_cast<QImage *>(d->device)->format();
497 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
498 d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
500 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
502 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
511 bool QRasterPaintEngine::end()
514 Q_D(QRasterPaintEngine);
515 qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
517 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
527 void QRasterPaintEngine::releaseBuffer()
529 Q_D(QRasterPaintEngine);
530 d->rasterBuffer.reset(new QRasterBuffer);
536 QSize QRasterPaintEngine::size() const
538 Q_D(const QRasterPaintEngine);
539 return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
546 void QRasterPaintEngine::saveBuffer(const QString &s) const
548 Q_D(const QRasterPaintEngine);
549 d->rasterBuffer->bufferImage().save(s, "PNG");
556 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
558 QRasterPaintEngineState *s = state();
559 // FALCON: get rid of this line, see drawImage call below.
561 QTransform::TransformationType txop = s->matrix.type();
565 case QTransform::TxNone:
566 s->flags.int_xform = true;
569 case QTransform::TxTranslate:
570 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
571 && qreal(int(s->matrix.dy())) == s->matrix.dy();
574 case QTransform::TxScale:
575 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
576 && qreal(int(s->matrix.dy())) == s->matrix.dy()
577 && qreal(int(s->matrix.m11())) == s->matrix.m11()
578 && qreal(int(s->matrix.m22())) == s->matrix.m22();
581 default: // shear / perspective...
582 s->flags.int_xform = false;
586 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
588 ensureOutlineMapper();
591 Q_D(QRasterPaintEngine);
592 d->isPlain45DegreeRotation = false;
593 if (txop >= QTransform::TxRotate) {
594 d->isPlain45DegreeRotation =
595 (qFuzzyIsNull(matrix.m11())
596 && qFuzzyIsNull(matrix.m12() - qreal(1))
597 && qFuzzyIsNull(matrix.m21() + qreal(1))
598 && qFuzzyIsNull(matrix.m22())
601 (qFuzzyIsNull(matrix.m11() + qreal(1))
602 && qFuzzyIsNull(matrix.m12())
603 && qFuzzyIsNull(matrix.m21())
604 && qFuzzyIsNull(matrix.m22() + qreal(1))
607 (qFuzzyIsNull(matrix.m11())
608 && qFuzzyIsNull(matrix.m12() + qreal(1))
609 && qFuzzyIsNull(matrix.m21() - qreal(1))
610 && qFuzzyIsNull(matrix.m22())
620 QRasterPaintEngineState::~QRasterPaintEngineState()
622 if (flags.has_clip_ownership)
627 QRasterPaintEngineState::QRasterPaintEngineState()
639 flags.fast_pen = true;
640 flags.antialiased = false;
641 flags.bilinear = false;
642 flags.fast_text = true;
643 flags.int_xform = true;
644 flags.tx_noshear = true;
645 flags.fast_images = true;
648 flags.has_clip_ownership = false;
653 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
658 , strokeFlags(s.strokeFlags)
659 , lastBrush(s.lastBrush)
660 , brushData(s.brushData)
661 , fillFlags(s.fillFlags)
662 , pixmapFlags(s.pixmapFlags)
663 , intOpacity(s.intOpacity)
667 , flag_bits(s.flag_bits)
669 brushData.tempImage = 0;
670 penData.tempImage = 0;
671 flags.has_clip_ownership = false;
677 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
679 QRasterPaintEngineState *s;
681 s = new QRasterPaintEngineState();
683 s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
691 void QRasterPaintEngine::setState(QPainterState *s)
693 Q_D(QRasterPaintEngine);
694 QPaintEngineEx::setState(s);
695 d->rasterBuffer->compositionMode = s->composition_mode;
699 \fn QRasterPaintEngineState *QRasterPaintEngine::state()
704 \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
711 void QRasterPaintEngine::penChanged()
714 qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
716 QRasterPaintEngineState *s = state();
717 s->strokeFlags |= DirtyPen;
718 s->dirty |= DirtyPen;
724 void QRasterPaintEngine::updatePen(const QPen &pen)
726 Q_D(QRasterPaintEngine);
727 QRasterPaintEngineState *s = state();
729 qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
732 Qt::PenStyle pen_style = qpen_style(pen);
737 s->penData.clip = d->clip();
738 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
740 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
741 || pen.brush().transform().type() >= QTransform::TxNone) {
742 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
745 // Slightly ugly handling of an uncommon case... We need to change
746 // the pen because it is reused in draw_midpoint to decide dashed
748 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
749 pen_style = Qt::SolidLine;
750 s->lastPen.setStyle(Qt::SolidLine);
753 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
754 d->basicStroker.setCapStyle(qpen_capStyle(pen));
755 d->basicStroker.setMiterLimit(pen.miterLimit());
757 qreal penWidth = qpen_widthf(pen);
759 d->basicStroker.setStrokeWidth(1);
761 d->basicStroker.setStrokeWidth(penWidth);
763 if(pen_style == Qt::SolidLine) {
764 s->stroker = &d->basicStroker;
765 } else if (pen_style != Qt::NoPen) {
767 d->dashStroker.reset(new QDashStroker(&d->basicStroker));
768 if (pen.isCosmetic()) {
769 d->dashStroker->setClipRect(d->deviceRect);
771 // ### I've seen this inverted devrect multiple places now...
772 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
773 d->dashStroker->setClipRect(clipRect);
775 d->dashStroker->setDashPattern(pen.dashPattern());
776 d->dashStroker->setDashOffset(pen.dashOffset());
777 s->stroker = d->dashStroker.data();
782 ensureState(); // needed because of tx_noshear...
783 s->flags.fast_pen = pen_style > Qt::NoPen
785 && ((pen.isCosmetic() && penWidth <= 1)
786 || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
788 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
798 void QRasterPaintEngine::brushOriginChanged()
800 QRasterPaintEngineState *s = state();
802 qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
805 s->fillFlags |= DirtyBrushOrigin;
812 void QRasterPaintEngine::brushChanged()
814 QRasterPaintEngineState *s = state();
816 qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
818 s->fillFlags |= DirtyBrush;
827 void QRasterPaintEngine::updateBrush(const QBrush &brush)
830 qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
832 Q_D(QRasterPaintEngine);
833 QRasterPaintEngineState *s = state();
834 // must set clip prior to setup, as setup uses it...
835 s->brushData.clip = d->clip();
836 s->brushData.setup(brush, s->intOpacity, s->composition_mode);
837 if (s->fillFlags & DirtyTransform
838 || brush.transform().type() >= QTransform::TxNone)
839 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
840 s->lastBrush = brush;
844 void QRasterPaintEngine::updateOutlineMapper()
846 Q_D(QRasterPaintEngine);
847 d->outlineMapper->setMatrix(state()->matrix);
850 void QRasterPaintEngine::updateState()
852 QRasterPaintEngineState *s = state();
854 if (s->dirty & DirtyTransform)
855 updateMatrix(s->matrix);
857 if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
858 const QPainter::CompositionMode mode = s->composition_mode;
859 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
860 && s->intOpacity == 256
861 && (mode == QPainter::CompositionMode_Source
862 || (mode == QPainter::CompositionMode_SourceOver
863 && qAlpha(s->penData.solid.color) == 255));
873 void QRasterPaintEngine::opacityChanged()
875 QRasterPaintEngineState *s = state();
878 qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
881 s->fillFlags |= DirtyOpacity;
882 s->strokeFlags |= DirtyOpacity;
883 s->pixmapFlags |= DirtyOpacity;
884 s->dirty |= DirtyOpacity;
885 s->intOpacity = (int) (s->opacity * 256);
891 void QRasterPaintEngine::compositionModeChanged()
893 Q_D(QRasterPaintEngine);
894 QRasterPaintEngineState *s = state();
897 qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
900 s->fillFlags |= DirtyCompositionMode;
901 s->dirty |= DirtyCompositionMode;
903 s->strokeFlags |= DirtyCompositionMode;
904 d->rasterBuffer->compositionMode = s->composition_mode;
906 d->recalculateFastImages();
912 void QRasterPaintEngine::renderHintsChanged()
914 QRasterPaintEngineState *s = state();
917 qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
920 bool was_aa = s->flags.antialiased;
921 bool was_bilinear = s->flags.bilinear;
923 s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
924 s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
926 if (was_aa != s->flags.antialiased)
927 s->strokeFlags |= DirtyHints;
929 if (was_bilinear != s->flags.bilinear) {
930 s->strokeFlags |= DirtyPen;
931 s->fillFlags |= DirtyBrush;
934 Q_D(QRasterPaintEngine);
935 d->recalculateFastImages();
941 void QRasterPaintEngine::transformChanged()
943 QRasterPaintEngineState *s = state();
946 qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
949 s->fillFlags |= DirtyTransform;
950 s->strokeFlags |= DirtyTransform;
952 s->dirty |= DirtyTransform;
954 Q_D(QRasterPaintEngine);
955 d->recalculateFastImages();
961 void QRasterPaintEngine::clipEnabledChanged()
963 QRasterPaintEngineState *s = state();
966 qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
970 s->clip->enabled = s->clipEnabled;
971 s->fillFlags |= DirtyClipEnabled;
972 s->strokeFlags |= DirtyClipEnabled;
973 s->pixmapFlags |= DirtyClipEnabled;
978 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
980 rasterBuffer->prepare(device);
984 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
986 SrcOverBlendFunc func,
991 if (alpha == 0 || !clip.isValid())
994 Q_ASSERT(img.depth() >= 8);
996 int srcBPL = img.bytesPerLine();
997 const uchar *srcBits = img.bits();
998 int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
999 int iw = img.width();
1000 int ih = img.height();
1002 if (!sr.isEmpty()) {
1005 // Adjust the image according to the source offset...
1006 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1009 // adapt the x parameters
1010 int x = qRound(pt.x());
1012 int cx2 = clip.x() + clip.width();
1015 srcBits += srcSize * d;
1020 int d = x + iw - cx2;
1026 // adapt the y paremeters...
1028 int cy2 = clip.y() + clip.height();
1029 int y = qRound(pt.y());
1032 srcBits += srcBPL * d;
1037 int d = y + ih - cy2;
1043 // call the blend function...
1044 int dstSize = rasterBuffer->bytesPerPixel();
1045 int dstBPL = rasterBuffer->bytesPerLine();
1046 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1053 void QRasterPaintEnginePrivate::systemStateChanged()
1055 QRect clipRect(0, 0,
1056 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1057 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1059 if (!systemClip.isEmpty()) {
1060 QRegion clippedDeviceRgn = systemClip & clipRect;
1061 deviceRect = clippedDeviceRgn.boundingRect();
1062 baseClip->setClipRegion(clippedDeviceRgn);
1064 deviceRect = clipRect;
1065 baseClip->setClipRect(deviceRect);
1067 #ifdef QT_DEBUG_DRAW
1068 qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1071 exDeviceRect = deviceRect;
1073 Q_Q(QRasterPaintEngine);
1074 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1075 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1076 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1079 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1081 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1084 Q_Q(QRasterPaintEngine);
1085 bool bilinear = q->state()->flags.bilinear;
1087 if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1088 spanData->setupMatrix(b.transform() * m, bilinear);
1090 if (m.type() <= QTransform::TxTranslate) {
1091 // specialize setupMatrix for translation matrices
1092 // to avoid needless matrix inversion
1100 spanData->dx = -m.dx();
1101 spanData->dy = -m.dy();
1102 spanData->txop = m.type();
1103 spanData->bilinear = bilinear;
1104 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1105 spanData->adjustSpanMethods();
1107 spanData->setupMatrix(m, bilinear);
1112 // #define QT_CLIPPING_RATIOS
1114 #ifdef QT_CLIPPING_RATIOS
1119 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1121 if (d->clip()->hasRectClip)
1123 if (d->clip()->hasRegionClip)
1127 if ((totalClips % 5000) == 0) {
1128 printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1129 rectClips * 100.0 / (qreal) totalClips,
1130 regionClips * 100.0 / (qreal) totalClips,
1131 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1140 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1142 if (s->flags.has_clip_ownership)
1145 s->flags.has_clip_ownership = false;
1148 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1150 s->fillFlags |= QPaintEngine::DirtyClipPath;
1151 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1152 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1154 d->solid_color_filler.clip = d->clip();
1155 d->solid_color_filler.adjustSpanMethods();
1157 #ifdef QT_DEBUG_DRAW
1158 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1167 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1169 #ifdef QT_DEBUG_DRAW
1170 qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1172 if (path.elements()) {
1173 for (int i=0; i<path.elementCount(); ++i) {
1174 qDebug() << " - " << path.elements()[i]
1175 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1178 for (int i=0; i<path.elementCount(); ++i) {
1179 qDebug() << " ---- "
1180 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1185 Q_D(QRasterPaintEngine);
1186 QRasterPaintEngineState *s = state();
1188 const qreal *points = path.points();
1189 const QPainterPath::ElementType *types = path.elements();
1191 // There are some cases that are not supported by clip(QRect)
1192 if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1193 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1194 if (s->matrix.type() <= QTransform::TxScale
1195 && ((path.shape() == QVectorPath::RectangleHint)
1196 || (isRect(points, path.elementCount())
1197 && (!types || (types[0] == QPainterPath::MoveToElement
1198 && types[1] == QPainterPath::LineToElement
1199 && types[2] == QPainterPath::LineToElement
1200 && types[3] == QPainterPath::LineToElement))))) {
1201 #ifdef QT_DEBUG_DRAW
1202 qDebug() << " --- optimizing vector clip to rect clip...";
1205 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1206 if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1211 if (op == Qt::NoClip) {
1212 qrasterpaintengine_state_setNoClip(s);
1215 QClipData *base = d->baseClip.data();
1217 // Intersect with current clip when available...
1218 if (op == Qt::IntersectClip && s->clip)
1221 // We always intersect, except when there is nothing to
1222 // intersect with, in which case we simplify the operation to
1224 Qt::ClipOperation isectOp = Qt::IntersectClip;
1226 isectOp = Qt::ReplaceClip;
1228 QClipData *newClip = new QClipData(d->rasterBuffer->height());
1229 newClip->initialize();
1230 ClipData clipData = { base, newClip, isectOp };
1231 ensureOutlineMapper();
1232 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1236 if (op == Qt::UniteClip) {
1238 QClipData *result = new QClipData(d->rasterBuffer->height());
1239 QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1240 qt_merge_clip(current, newClip, result);
1248 if (s->flags.has_clip_ownership)
1252 s->flags.has_clip_ownership = true;
1254 qrasterpaintengine_dirty_clip(d, s);
1262 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1264 #ifdef QT_DEBUG_DRAW
1265 qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1268 QRasterPaintEngineState *s = state();
1270 if (op == Qt::NoClip) {
1271 qrasterpaintengine_state_setNoClip(s);
1273 } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1274 QPaintEngineEx::clip(rect, op);
1277 } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1278 QPaintEngineEx::clip(rect, op);
1284 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1286 Q_D(QRasterPaintEngine);
1287 QRect clipRect = r & d->deviceRect;
1288 QRasterPaintEngineState *s = state();
1290 if (op == Qt::ReplaceClip || s->clip == 0) {
1292 // No current clip, hence we intersect with sysclip and be
1294 QRegion clipRegion = systemClip();
1295 QClipData *clip = new QClipData(d->rasterBuffer->height());
1297 if (clipRegion.isEmpty())
1298 clip->setClipRect(clipRect);
1300 clip->setClipRegion(clipRegion & clipRect);
1302 if (s->flags.has_clip_ownership)
1306 s->clip->enabled = true;
1307 s->flags.has_clip_ownership = true;
1309 } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1310 QClipData *base = s->clip;
1313 if (base->hasRectClip || base->hasRegionClip) {
1314 if (!s->flags.has_clip_ownership) {
1315 s->clip = new QClipData(d->rasterBuffer->height());
1316 s->flags.has_clip_ownership = true;
1318 if (base->hasRectClip)
1319 s->clip->setClipRect(base->clipRect & clipRect);
1321 s->clip->setClipRegion(base->clipRegion & clipRect);
1322 s->clip->enabled = true;
1330 qrasterpaintengine_dirty_clip(d, s);
1338 void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
1340 #ifdef QT_DEBUG_DRAW
1341 qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1344 Q_D(QRasterPaintEngine);
1346 if (region.rectCount() == 1) {
1347 clip(region.boundingRect(), op);
1351 QRasterPaintEngineState *s = state();
1352 const QClipData *clip = d->clip();
1353 const QClipData *baseClip = d->baseClip.data();
1355 if (op == Qt::NoClip) {
1356 qrasterpaintengine_state_setNoClip(s);
1357 } else if (s->matrix.type() > QTransform::TxScale
1358 || op == Qt::UniteClip
1359 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1360 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1361 QPaintEngineEx::clip(region, op);
1363 const QClipData *curClip;
1366 if (op == Qt::IntersectClip)
1371 if (s->flags.has_clip_ownership) {
1375 newClip = new QClipData(d->rasterBuffer->height());
1377 s->flags.has_clip_ownership = true;
1380 QRegion r = s->matrix.map(region);
1381 if (curClip->hasRectClip)
1382 newClip->setClipRegion(r & curClip->clipRect);
1383 else if (curClip->hasRegionClip)
1384 newClip->setClipRegion(r & curClip->clipRegion);
1386 qrasterpaintengine_dirty_clip(d, s);
1393 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1395 #ifdef QT_DEBUG_DRAW
1396 qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1399 if (!fillData->blend)
1402 Q_D(QRasterPaintEngine);
1404 const QRectF controlPointRect = path.controlPointRect();
1406 QRasterPaintEngineState *s = state();
1407 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1408 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1409 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1410 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1411 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1412 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1414 if (!s->flags.antialiased && !do_clip) {
1415 d->initializeRasterizer(fillData);
1416 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1420 ensureOutlineMapper();
1421 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1424 static void fillRect_normalized(const QRect &r, QSpanData *data,
1425 QRasterPaintEnginePrivate *pe)
1429 bool rectClipped = true;
1432 x1 = qMax(r.x(), data->clip->xmin);
1433 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1434 y1 = qMax(r.y(), data->clip->ymin);
1435 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1436 rectClipped = data->clip->hasRectClip;
1439 x1 = qMax(r.x(), pe->deviceRect.x());
1440 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1441 y1 = qMax(r.y(), pe->deviceRect.y());
1442 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1444 x1 = qMax(r.x(), 0);
1445 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1446 y1 = qMax(r.y(), 0);
1447 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1450 if (x2 <= x1 || y2 <= y1)
1453 const int width = x2 - x1;
1454 const int height = y2 - y1;
1456 bool isUnclipped = rectClipped
1457 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1459 if (pe && isUnclipped) {
1460 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1462 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1463 || (mode == QPainter::CompositionMode_SourceOver
1464 && qAlpha(data->solid.color) == 255)))
1466 data->fillRect(data->rasterBuffer, x1, y1, width, height,
1472 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1474 const int nspans = 256;
1475 QT_FT_Span spans[nspans];
1477 Q_ASSERT(data->blend);
1480 int n = qMin(nspans, y2 - y);
1484 spans[i].len = width;
1486 spans[i].coverage = 255;
1490 blend(n, spans, data);
1498 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1500 #ifdef QT_DEBUG_DRAW
1501 qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1503 Q_D(QRasterPaintEngine);
1505 QRasterPaintEngineState *s = state();
1509 if (s->brushData.blend) {
1510 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1511 const QRect *r = rects;
1512 const QRect *lastRect = rects + rectCount;
1514 int offset_x = int(s->matrix.dx());
1515 int offset_y = int(s->matrix.dy());
1516 while (r < lastRect) {
1517 QRect rect = r->normalized();
1518 QRect rr = rect.translated(offset_x, offset_y);
1519 fillRect_normalized(rr, &s->brushData, d);
1523 QRectVectorPath path;
1524 for (int i=0; i<rectCount; ++i) {
1526 fill(path, s->brush);
1532 if (s->penData.blend) {
1533 QRectVectorPath path;
1534 if (s->flags.fast_pen) {
1535 QCosmeticStroker stroker(s, d->deviceRect);
1536 for (int i = 0; i < rectCount; ++i) {
1538 stroker.drawPath(path);
1541 for (int i = 0; i < rectCount; ++i) {
1543 stroke(path, s->pen);
1552 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1554 #ifdef QT_DEBUG_DRAW
1555 qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1557 #ifdef QT_FAST_SPANS
1558 Q_D(QRasterPaintEngine);
1560 QRasterPaintEngineState *s = state();
1563 if (s->flags.tx_noshear) {
1565 if (s->brushData.blend) {
1566 d->initializeRasterizer(&s->brushData);
1567 for (int i = 0; i < rectCount; ++i) {
1568 const QRectF &rect = rects[i].normalized();
1571 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1572 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1573 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1578 if (s->penData.blend) {
1579 QRectVectorPath path;
1580 if (s->flags.fast_pen) {
1581 QCosmeticStroker stroker(s, d->deviceRect);
1582 for (int i = 0; i < rectCount; ++i) {
1584 stroker.drawPath(path);
1587 for (int i = 0; i < rectCount; ++i) {
1589 QPaintEngineEx::stroke(path, s->lastPen);
1596 #endif // QT_FAST_SPANS
1597 QPaintEngineEx::drawRects(rects, rectCount);
1604 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1606 Q_D(QRasterPaintEngine);
1607 QRasterPaintEngineState *s = state();
1610 if (!s->penData.blend)
1613 if (s->flags.fast_pen) {
1614 QCosmeticStroker stroker(s, d->deviceRect);
1615 stroker.drawPath(path);
1616 } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1617 qreal width = s->lastPen.isCosmetic()
1618 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1619 : qpen_widthf(s->lastPen) * s->txscale;
1621 qreal dashOffset = s->lastPen.dashOffset();
1623 qreal patternLength = 0;
1624 const QVector<qreal> pattern = s->lastPen.dashPattern();
1625 for (int i = 0; i < pattern.size(); ++i)
1626 patternLength += pattern.at(i);
1628 if (patternLength > 0) {
1629 int n = qFloor(dashOffset / patternLength);
1630 dashOffset -= n * patternLength;
1631 while (dashOffset >= pattern.at(dashIndex)) {
1632 dashOffset -= pattern.at(dashIndex);
1633 if (++dashIndex >= pattern.size())
1639 Q_D(QRasterPaintEngine);
1640 d->initializeRasterizer(&s->penData);
1641 int lineCount = path.elementCount() / 2;
1642 const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1644 for (int i = 0; i < lineCount; ++i) {
1645 if (lines[i].p1() == lines[i].p2()) {
1646 if (s->lastPen.capStyle() != Qt::FlatCap) {
1647 QPointF p = lines[i].p1();
1648 QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1649 QPointF(p.x() + width*0.5, p.y())));
1650 d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1655 const QLineF line = s->matrix.map(lines[i]);
1656 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1657 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1658 width / line.length(),
1659 s->lastPen.capStyle() == Qt::SquareCap);
1661 d->rasterizeLine_dashed(line, width,
1662 &dashIndex, &dashOffset, &inDash);
1667 QPaintEngineEx::stroke(path, pen);
1670 static inline QRect toNormalizedFillRect(const QRectF &rect)
1672 int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1673 int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1674 int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1675 int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1682 return QRect(x1, y1, x2 - x1, y2 - y1);
1688 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1692 #ifdef QT_DEBUG_DRAW
1693 QRectF rf = path.controlPointRect();
1694 qDebug() << "QRasterPaintEngine::fill(): "
1695 << "size=" << path.elementCount()
1696 << ", hints=" << hex << path.hints()
1700 Q_D(QRasterPaintEngine);
1701 QRasterPaintEngineState *s = state();
1704 if (!s->brushData.blend)
1707 if (path.shape() == QVectorPath::RectangleHint) {
1708 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1709 const qreal *p = path.points();
1710 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1711 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1712 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1716 if (s->flags.tx_noshear) {
1717 d->initializeRasterizer(&s->brushData);
1718 // ### Is normalizing really necessary here?
1719 const qreal *p = path.points();
1720 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1722 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1723 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1724 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1730 // ### Optimize for non transformed ellipses and rectangles...
1731 QRectF cpRect = path.controlPointRect();
1732 const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1733 ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1736 // const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1737 // || deviceRect.right() > QT_RASTER_COORD_LIMIT
1738 // || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1739 // || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1741 // ### Falonc: implement....
1742 // if (!s->flags.antialiased && !do_clip) {
1743 // d->initializeRasterizer(&s->brushData);
1744 // d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1748 ensureOutlineMapper();
1749 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1752 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1754 Q_D(QRasterPaintEngine);
1755 QRasterPaintEngineState *s = state();
1757 if (!s->flags.antialiased) {
1758 uint txop = s->matrix.type();
1759 if (txop == QTransform::TxNone) {
1760 fillRect_normalized(toNormalizedFillRect(r), data, d);
1762 } else if (txop == QTransform::TxTranslate) {
1763 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1764 fillRect_normalized(rr, data, d);
1766 } else if (txop == QTransform::TxScale) {
1767 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1768 fillRect_normalized(rr, data, d);
1773 if (s->flags.tx_noshear) {
1774 d->initializeRasterizer(data);
1775 QRectF nr = r.normalized();
1776 if (!nr.isEmpty()) {
1777 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1778 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1779 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1786 ensureOutlineMapper();
1787 fillPath(path, data);
1793 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1795 #ifdef QT_DEBUG_DRAW
1796 qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1798 QRasterPaintEngineState *s = state();
1801 if (!s->brushData.blend)
1804 fillRect(r, &s->brushData);
1810 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1812 #ifdef QT_DEBUG_DRAW
1813 qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1815 Q_D(QRasterPaintEngine);
1816 QRasterPaintEngineState *s = state();
1818 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1819 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1820 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1823 d->solid_color_filler.clip = d->clip();
1824 d->solid_color_filler.adjustSpanMethods();
1825 fillRect(r, &d->solid_color_filler);
1828 static inline bool isAbove(const QPointF *a, const QPointF *b)
1830 return a->y() < b->y();
1833 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1838 Q_ASSERT(pointCount >= 2);
1840 QVector<const QPointF *> sorted;
1841 sorted.reserve(pointCount);
1843 upper->reserve(pointCount * 3 / 4);
1844 lower->reserve(pointCount * 3 / 4);
1846 for (int i = 0; i < pointCount; ++i)
1847 sorted << points + i;
1849 qSort(sorted.begin(), sorted.end(), isAbove);
1851 qreal splitY = sorted.at(sorted.size() / 2)->y();
1853 const QPointF *end = points + pointCount;
1854 const QPointF *last = end - 1;
1856 QVector<QPointF> *bin[2] = { upper, lower };
1858 for (const QPointF *p = points; p < end; ++p) {
1859 int side = p->y() < splitY;
1860 int lastSide = last->y() < splitY;
1862 if (side != lastSide) {
1863 if (qFuzzyCompare(p->y(), splitY)) {
1864 bin[!side]->append(*p);
1865 } else if (qFuzzyCompare(last->y(), splitY)) {
1866 bin[side]->append(*last);
1868 QPointF delta = *p - *last;
1869 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1871 bin[0]->append(intersection);
1872 bin[1]->append(intersection);
1876 bin[side]->append(*p);
1881 // give up if we couldn't reduce the point count
1882 return upper->size() < pointCount && lower->size() < pointCount;
1888 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1890 Q_D(QRasterPaintEngine);
1891 QRasterPaintEngineState *s = state();
1893 const int maxPoints = 0xffff;
1895 // max amount of points that raster engine can reliably handle
1896 if (pointCount > maxPoints) {
1897 QVector<QPointF> upper, lower;
1899 if (splitPolygon(points, pointCount, &upper, &lower)) {
1900 fillPolygon(upper.constData(), upper.size(), mode);
1901 fillPolygon(lower.constData(), lower.size(), mode);
1903 qWarning("Polygon too complex for filling.");
1908 // Compose polygon fill..,
1909 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1910 ensureOutlineMapper();
1911 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1914 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1916 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1922 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1924 Q_D(QRasterPaintEngine);
1925 QRasterPaintEngineState *s = state();
1927 #ifdef QT_DEBUG_DRAW
1928 qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1929 for (int i=0; i<pointCount; ++i)
1930 qDebug() << " - " << points[i];
1932 Q_ASSERT(pointCount >= 2);
1934 if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1935 QRectF r(points[0], points[2]);
1941 if (mode != PolylineMode) {
1944 if (s->brushData.blend) {
1945 d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
1946 fillPolygon(points, pointCount, mode);
1947 d->outlineMapper->setCoordinateRounding(false);
1951 // Do the outline...
1952 if (s->penData.blend) {
1953 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1954 if (s->flags.fast_pen) {
1955 QCosmeticStroker stroker(s, d->deviceRect);
1956 stroker.drawPath(vp);
1958 QPaintEngineEx::stroke(vp, s->lastPen);
1966 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1968 Q_D(QRasterPaintEngine);
1969 QRasterPaintEngineState *s = state();
1971 #ifdef QT_DEBUG_DRAW
1972 qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1973 for (int i=0; i<pointCount; ++i)
1974 qDebug() << " - " << points[i];
1976 Q_ASSERT(pointCount >= 2);
1977 if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1978 QRect r(points[0].x(),
1980 points[2].x() - points[0].x(),
1981 points[2].y() - points[0].y());
1989 if (mode != PolylineMode) {
1991 if (s->brushData.blend) {
1992 // Compose polygon fill..,
1993 ensureOutlineMapper();
1994 d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
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());
2008 d->outlineMapper->setCoordinateRounding(false);
2012 // Do the outline...
2013 if (s->penData.blend) {
2014 int count = pointCount * 2;
2015 QVarLengthArray<qreal> fpoints(count);
2016 for (int i=0; i<count; ++i)
2017 fpoints[i] = ((int *) points)[i];
2018 QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2020 if (s->flags.fast_pen) {
2021 QCosmeticStroker stroker(s, d->deviceRect);
2022 stroker.drawPath(vp);
2024 QPaintEngineEx::stroke(vp, s->lastPen);
2032 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2034 #ifdef QT_DEBUG_DRAW
2035 qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2038 QPixmapData *pd = pixmap.pixmapData();
2039 if (pd->classId() == QPixmapData::RasterClass) {
2040 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2041 if (image.depth() == 1) {
2042 Q_D(QRasterPaintEngine);
2043 QRasterPaintEngineState *s = state();
2044 if (s->matrix.type() <= QTransform::TxTranslate) {
2046 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2048 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2051 QRasterPaintEngine::drawImage(pos, image);
2054 const QImage image = pixmap.toImage();
2055 if (pixmap.depth() == 1) {
2056 Q_D(QRasterPaintEngine);
2057 QRasterPaintEngineState *s = state();
2058 if (s->matrix.type() <= QTransform::TxTranslate) {
2060 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2062 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2065 QRasterPaintEngine::drawImage(pos, image);
2073 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2075 #ifdef QT_DEBUG_DRAW
2076 qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2079 QPixmapData* pd = pixmap.pixmapData();
2080 if (pd->classId() == QPixmapData::RasterClass) {
2081 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2082 if (image.depth() == 1) {
2083 Q_D(QRasterPaintEngine);
2084 QRasterPaintEngineState *s = state();
2085 if (s->matrix.type() <= QTransform::TxTranslate
2086 && r.size() == sr.size()
2087 && r.size() == pixmap.size()) {
2089 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2092 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2095 drawImage(r, image, sr);
2098 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2099 const QImage image = pd->toImage(clippedSource);
2100 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2101 if (image.depth() == 1) {
2102 Q_D(QRasterPaintEngine);
2103 QRasterPaintEngineState *s = state();
2104 if (s->matrix.type() <= QTransform::TxTranslate
2105 && r.size() == sr.size()
2106 && r.size() == pixmap.size()) {
2108 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2111 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2114 drawImage(r, image, translatedSource);
2119 // assumes that rect has positive width and height
2120 static inline const QRect toRect_normalized(const QRectF &rect)
2122 const int x = qRound(rect.x());
2123 const int y = qRound(rect.y());
2124 const int w = int(rect.width() + qreal(0.5));
2125 const int h = int(rect.height() + qreal(0.5));
2127 return QRect(x, y, w, h);
2130 static inline int fast_ceil_positive(const qreal &v)
2132 const int iv = int(v);
2139 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2141 const int xmin = int(rect.x());
2142 const int xmax = int(fast_ceil_positive(rect.right()));
2143 const int ymin = int(rect.y());
2144 const int ymax = int(fast_ceil_positive(rect.bottom()));
2145 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2151 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2153 #ifdef QT_DEBUG_DRAW
2154 qDebug() << " - QRasterPaintEngine::drawImage(), p=" << p << " image=" << img.size() << "depth=" << img.depth();
2157 Q_D(QRasterPaintEngine);
2158 QRasterPaintEngineState *s = state();
2160 if (s->matrix.type() > QTransform::TxTranslate) {
2161 drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2163 QRectF(0, 0, img.width(), img.height()));
2166 const QClipData *clip = d->clip();
2167 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2169 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2170 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2173 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2175 } else if (clip->hasRectClip) {
2176 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2184 d->image_filler.clip = clip;
2185 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2186 if (!d->image_filler.blend)
2188 d->image_filler.dx = -pt.x();
2189 d->image_filler.dy = -pt.y();
2190 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2192 fillRect_normalized(rr, &d->image_filler, d);
2197 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2199 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2210 inline RotationType qRotationType(const QTransform &transform)
2212 QTransform::TransformationType type = transform.type();
2214 if (type > QTransform::TxRotate)
2217 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2218 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2221 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2222 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2225 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2226 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2232 inline bool isPixelAligned(const QRectF &rect) {
2233 return QRectF(rect.toRect()) == rect;
2240 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2241 Qt::ImageConversionFlags)
2243 #ifdef QT_DEBUG_DRAW
2244 qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2250 Q_D(QRasterPaintEngine);
2251 QRasterPaintEngineState *s = state();
2252 int sr_l = qFloor(sr.left());
2253 int sr_r = qCeil(sr.right()) - 1;
2254 int sr_t = qFloor(sr.top());
2255 int sr_b = qCeil(sr.bottom()) - 1;
2257 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2258 // as fillRect will apply the aliased coordinate delta we need to
2259 // subtract it here as we don't use it for image drawing
2260 QTransform old = s->matrix;
2261 s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2263 // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2264 QRgb color = img.pixel(sr_l, sr_t);
2265 switch (img.format()) {
2266 case QImage::Format_ARGB32_Premultiplied:
2267 case QImage::Format_ARGB8565_Premultiplied:
2268 case QImage::Format_ARGB6666_Premultiplied:
2269 case QImage::Format_ARGB8555_Premultiplied:
2270 case QImage::Format_ARGB4444_Premultiplied:
2271 // Combine premultiplied color with the opacity set on the painter.
2272 d->solid_color_filler.solid.color =
2273 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2274 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2277 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2281 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2282 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2286 d->solid_color_filler.clip = d->clip();
2287 d->solid_color_filler.adjustSpanMethods();
2288 fillRect(r, &d->solid_color_filler);
2294 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2296 const QClipData *clip = d->clip();
2298 if (s->matrix.type() > QTransform::TxTranslate
2300 && (!clip || clip->hasRectClip)
2301 && s->intOpacity == 256
2302 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2303 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2304 && d->rasterBuffer->format == img.format()
2305 && (d->rasterBuffer->format == QImage::Format_RGB16
2306 || d->rasterBuffer->format == QImage::Format_RGB32
2307 || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2308 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2310 RotationType rotationType = qRotationType(s->matrix);
2312 if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2313 QRectF transformedTargetRect = s->matrix.mapRect(r);
2315 if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2316 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2318 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2319 if (clippedTransformedTargetRect.isNull())
2322 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2324 QRect clippedSourceRect
2325 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2326 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2328 uint dbpl = d->rasterBuffer->bytesPerLine();
2329 uint sbpl = img.bytesPerLine();
2331 uchar *dst = d->rasterBuffer->buffer();
2332 uint bpp = img.depth() >> 3;
2334 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2335 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2337 uint cw = clippedSourceRect.width();
2338 uint ch = clippedSourceRect.height();
2340 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2347 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2349 QRectF targetBounds = s->matrix.mapRect(r);
2350 bool exceedsPrecision = targetBounds.width() > 0xffff
2351 || targetBounds.height() > 0xffff;
2353 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2354 if (s->matrix.type() > QTransform::TxScale) {
2355 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2356 if (func && (!clip || clip->hasRectClip)) {
2357 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2358 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2359 s->matrix, s->intOpacity);
2363 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2364 if (func && (!clip || clip->hasRectClip)) {
2365 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2366 img.bits(), img.bytesPerLine(),
2367 qt_mapRect_non_normalizing(r, s->matrix), sr,
2368 !clip ? d->deviceRect : clip->clipRect,
2375 QTransform copy = s->matrix;
2376 copy.translate(r.x(), r.y());
2378 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2379 copy.translate(-sr.x(), -sr.y());
2381 d->image_filler_xform.clip = clip;
2382 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2383 if (!d->image_filler_xform.blend)
2385 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2387 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2388 QRectF rr = s->matrix.mapRect(r);
2390 const int x1 = qRound(rr.x());
2391 const int y1 = qRound(rr.y());
2392 const int x2 = qRound(rr.right());
2393 const int y2 = qRound(rr.bottom());
2395 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2399 #ifdef QT_FAST_SPANS
2401 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2402 d->initializeRasterizer(&d->image_filler_xform);
2403 d->rasterizer->setAntialiased(s->flags.antialiased);
2405 const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2407 const QRectF &rect = r.normalized();
2408 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2409 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2411 if (s->flags.tx_noshear)
2412 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2414 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2418 const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2421 QTransform m = s->matrix;
2422 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2423 m.m21(), m.m22(), m.m23(),
2424 m.m31() - offs, m.m32() - offs, m.m33());
2425 fillPath(path, &d->image_filler_xform);
2428 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2429 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2431 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2433 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2435 } else if (clip->hasRectClip) {
2436 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2442 d->image_filler.clip = clip;
2443 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2444 if (!d->image_filler.blend)
2446 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2447 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2450 rr.translate(s->matrix.dx(), s->matrix.dy());
2452 const int x1 = qRound(rr.x());
2453 const int y1 = qRound(rr.y());
2454 const int x2 = qRound(rr.right());
2455 const int y2 = qRound(rr.bottom());
2457 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2464 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2466 #ifdef QT_DEBUG_DRAW
2467 qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2469 Q_D(QRasterPaintEngine);
2470 QRasterPaintEngineState *s = state();
2474 QPixmapData *pd = pixmap.pixmapData();
2475 if (pd->classId() == QPixmapData::RasterClass) {
2476 image = static_cast<QRasterPixmapData *>(pd)->image;
2478 image = pixmap.toImage();
2481 if (image.depth() == 1)
2482 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2484 if (s->matrix.type() > QTransform::TxTranslate) {
2485 QTransform copy = s->matrix;
2486 copy.translate(r.x(), r.y());
2487 copy.translate(-sr.x(), -sr.y());
2488 d->image_filler_xform.clip = d->clip();
2489 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2490 if (!d->image_filler_xform.blend)
2492 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2494 #ifdef QT_FAST_SPANS
2496 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2497 d->initializeRasterizer(&d->image_filler_xform);
2498 d->rasterizer->setAntialiased(s->flags.antialiased);
2500 const QRectF &rect = r.normalized();
2501 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2502 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2503 if (s->flags.tx_noshear)
2504 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2506 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2512 fillPath(path, &d->image_filler_xform);
2514 d->image_filler.clip = d->clip();
2516 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2517 if (!d->image_filler.blend)
2519 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2520 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2523 rr.translate(s->matrix.dx(), s->matrix.dy());
2524 fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2530 static inline bool monoVal(const uchar* s, int x)
2532 return (s[x>>3] << (x&7)) & 0x80;
2538 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2540 Q_D(QRasterPaintEngine);
2541 QRasterPaintEngineState *s = state();
2543 if (!s->penData.blend)
2546 QRasterBuffer *rb = d->rasterBuffer.data();
2548 const QRect rect(rx, ry, w, h);
2549 const QClipData *clip = d->clip();
2550 bool unclipped = false;
2552 // inlined QRect::intersects
2553 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2554 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2556 if (clip->hasRectClip) {
2557 unclipped = rx > clip->xmin
2558 && rx + w < clip->xmax
2560 && ry + h < clip->ymax;
2566 // inlined QRect::intersects
2567 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2568 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2572 // inlined QRect::contains
2573 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2574 && rect.top() >= 0 && rect.bottom() < rb->height();
2576 unclipped = contains && d->isUnclipped_normalized(rect);
2579 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2580 const uchar * scanline = static_cast<const uchar *>(src);
2582 if (s->flags.fast_text) {
2585 if (s->penData.bitmapBlit) {
2586 s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2587 scanline, w, h, bpl);
2590 } else if (depth == 8) {
2591 if (s->penData.alphamapBlit) {
2592 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2593 scanline, w, h, bpl, 0);
2596 } else if (depth == 32) {
2597 // (A)RGB Alpha mask where the alpha component is not used.
2598 if (s->penData.alphaRGBBlit) {
2599 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2600 (const uint *) scanline, w, h, bpl / 4, 0);
2604 } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2605 // (A)RGB Alpha mask where the alpha component is not used.
2607 int nx = qMax(0, rx);
2608 int ny = qMax(0, ry);
2610 // Move scanline pointer to compensate for moved x and y
2611 int xdiff = nx - rx;
2612 int ydiff = ny - ry;
2613 scanline += ydiff * bpl;
2614 scanline += xdiff * (depth == 32 ? 4 : 1);
2619 if (nx + w > d->rasterBuffer->width())
2620 w = d->rasterBuffer->width() - nx;
2621 if (ny + h > d->rasterBuffer->height())
2622 h = d->rasterBuffer->height() - ny;
2627 if (depth == 8 && s->penData.alphamapBlit) {
2628 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2629 scanline, w, h, bpl, clip);
2630 } else if (depth == 32 && s->penData.alphaRGBBlit) {
2631 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2632 (const uint *) scanline, w, h, bpl / 4, clip);
2647 scanline += bpl * y0;
2651 w = qMin(w, rb->width() - qMax(0, rx));
2652 h = qMin(h, rb->height() - qMax(0, ry));
2654 if (w <= 0 || h <= 0)
2657 const int NSPANS = 256;
2658 QSpan spans[NSPANS];
2661 const int x1 = x0 + w;
2662 const int y1 = y0 + h;
2665 for (int y = y0; y < y1; ++y) {
2666 for (int x = x0; x < x1; ) {
2667 if (!monoVal(scanline, x)) {
2672 if (current == NSPANS) {
2673 blend(current, spans, &s->penData);
2676 spans[current].x = x + rx;
2677 spans[current].y = y + ry;
2678 spans[current].coverage = 255;
2681 // extend span until we find a different one.
2682 while (x < x1 && monoVal(scanline, x)) {
2686 spans[current].len = len;
2691 } else if (depth == 8) {
2692 for (int y = y0; y < y1; ++y) {
2693 for (int x = x0; x < x1; ) {
2694 // Skip those with 0 coverage
2695 if (scanline[x] == 0) {
2700 if (current == NSPANS) {
2701 blend(current, spans, &s->penData);
2704 int coverage = scanline[x];
2705 spans[current].x = x + rx;
2706 spans[current].y = y + ry;
2707 spans[current].coverage = coverage;
2711 // extend span until we find a different one.
2712 while (x < x1 && scanline[x] == coverage) {
2716 spans[current].len = len;
2721 } else { // 32-bit alpha...
2722 uint *sl = (uint *) src;
2723 for (int y = y0; y < y1; ++y) {
2724 for (int x = x0; x < x1; ) {
2725 // Skip those with 0 coverage
2726 if ((sl[x] & 0x00ffffff) == 0) {
2731 if (current == NSPANS) {
2732 blend(current, spans, &s->penData);
2735 uint rgbCoverage = sl[x];
2736 int coverage = qGreen(rgbCoverage);
2737 spans[current].x = x + rx;
2738 spans[current].y = y + ry;
2739 spans[current].coverage = coverage;
2743 // extend span until we find a different one.
2744 while (x < x1 && sl[x] == rgbCoverage) {
2748 spans[current].len = len;
2751 sl += bpl / sizeof(uint);
2754 // qDebug() << "alphaPenBlt: num spans=" << current
2755 // << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2756 // Call span func for current set of spans.
2758 blend(current, spans, &s->penData);
2761 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2762 const QFixedPoint *positions, QFontEngine *fontEngine)
2764 Q_D(QRasterPaintEngine);
2765 QRasterPaintEngineState *s = state();
2767 #if !defined(QT_NO_FREETYPE)
2768 if (fontEngine->type() == QFontEngine::Freetype) {
2769 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2770 QFontEngineFT::GlyphFormat neededFormat =
2771 painter()->device()->devType() == QInternal::Widget
2772 ? fe->defaultGlyphFormat()
2773 : QFontEngineFT::Format_A8;
2775 if (d_func()->mono_surface
2776 || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2778 neededFormat = QFontEngineFT::Format_Mono;
2780 if (neededFormat == QFontEngineFT::Format_None)
2781 neededFormat = QFontEngineFT::Format_A8;
2783 QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2784 if (s->matrix.type() >= QTransform::TxScale) {
2785 if (s->matrix.isAffine())
2786 gset = fe->loadTransformedGlyphSet(s->matrix);
2791 if (!gset || gset->outline_drawing
2792 || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2795 FT_Face lockedFace = 0;
2798 switch (neededFormat) {
2799 case QFontEngineFT::Format_Mono:
2802 case QFontEngineFT::Format_A8:
2805 case QFontEngineFT::Format_A32:
2813 for (int i = 0; i < numGlyphs; i++) {
2814 QFixed spp = fe->subPixelPositionForX(positions[i].x);
2815 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2817 if (!glyph || glyph->format != neededFormat) {
2819 lockedFace = fe->lockFace();
2820 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2823 if (!glyph || !glyph->data)
2827 switch (neededFormat) {
2828 case QFontEngineFT::Format_Mono:
2829 pitch = ((glyph->width + 31) & ~31) >> 3;
2831 case QFontEngineFT::Format_A8:
2832 pitch = (glyph->width + 3) & ~3;
2834 case QFontEngineFT::Format_A32:
2835 pitch = glyph->width * 4;
2842 alphaPenBlt(glyph->data, pitch, depth,
2843 qFloor(positions[i].x) + glyph->x,
2844 qFloor(positions[i].y) - glyph->y,
2845 glyph->width, glyph->height);
2852 QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2854 QImageTextureGlyphCache *cache =
2855 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2857 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2858 fontEngine->setGlyphCache(0, cache);
2861 cache->populate(fontEngine, numGlyphs, glyphs, positions);
2862 cache->fillInPendingGlyphs();
2864 const QImage &image = cache->image();
2865 int bpl = image.bytesPerLine();
2867 int depth = image.depth();
2871 leftShift = 2; // multiply by 4
2872 else if (depth == 1)
2873 rightShift = 3; // divide by 8
2875 int margin = cache->glyphMargin();
2876 const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2877 const uchar *bits = image.bits();
2878 for (int i=0; i<numGlyphs; ++i) {
2880 QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2881 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2882 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2886 int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
2887 int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2889 // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2892 // c.baseLineX, c.baseLineY,
2895 // positions[i].x.toInt(), positions[i].y.toInt());
2897 alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2903 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2904 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2906 Q_D(QRasterPaintEngine);
2907 QRasterPaintEngineState *s = state();
2909 QFontEngine *fontEngine = ti.fontEngine;
2910 if (fontEngine->type() != QFontEngine::S60FontEngine) {
2911 QPaintEngineEx::drawTextItem(p, ti);
2915 QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2917 QVarLengthArray<QFixedPoint> positions;
2918 QVarLengthArray<glyph_t> glyphs;
2919 QTransform matrix = s->matrix;
2920 matrix.translate(p.x(), p.y());
2921 if (matrix.type() == QTransform::TxScale)
2922 fe->setFontScale(matrix.m11());
2923 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2924 const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2926 for (int i=0; i<glyphs.size(); ++i) {
2927 TOpenFontCharMetrics tmetrics;
2928 const TUint8 *glyphBitmapBytes;
2929 TSize glyphBitmapSize;
2930 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2931 const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
2932 const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
2933 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2936 if (matrix.type() == QTransform::TxScale)
2937 fe->setFontScale(1.0);
2941 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2944 * Returns true if the rectangle is completely within the current clip
2945 * state of the paint engine.
2947 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2949 const QClipData *cl = clip();
2951 // inline contains() for performance (we know the rects are normalized)
2952 const QRect &r1 = deviceRect;
2953 return (r.left() >= r1.left() && r.right() <= r1.right()
2954 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2958 if (cl->hasRectClip) {
2959 // currently all painting functions clips to deviceRect internally
2960 if (cl->clipRect == deviceRect)
2963 // inline contains() for performance (we know the rects are normalized)
2964 const QRect &r1 = cl->clipRect;
2965 return (r.left() >= r1.left() && r.right() <= r1.right()
2966 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2968 return qt_region_strictContains(cl->clipRegion, r);
2972 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2975 Q_Q(const QRasterPaintEngine);
2976 const QRasterPaintEngineState *s = q->state();
2977 const QClipData *cl = clip();
2979 QRect r = rect.normalized();
2980 // inline contains() for performance (we know the rects are normalized)
2981 const QRect &r1 = deviceRect;
2982 return (r.left() >= r1.left() && r.right() <= r1.right()
2983 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2987 // currently all painting functions that call this function clip to deviceRect internally
2988 if (cl->hasRectClip && cl->clipRect == deviceRect)
2991 if (s->flags.antialiased)
2994 QRect r = rect.normalized();
2996 r.setX(r.x() - penWidth);
2997 r.setY(r.y() - penWidth);
2998 r.setWidth(r.width() + 2 * penWidth);
2999 r.setHeight(r.height() + 2 * penWidth);
3002 if (cl->hasRectClip) {
3003 // inline contains() for performance (we know the rects are normalized)
3004 const QRect &r1 = cl->clipRect;
3005 return (r.left() >= r1.left() && r.right() <= r1.right()
3006 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3008 return qt_region_strictContains(cl->clipRegion, r);
3012 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3015 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3019 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3020 const QSpanData *data) const
3022 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3026 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3027 const QSpanData *data) const
3029 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3035 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3040 QFontEngine *fontEngine = textItem->fontEngine();
3041 if (!supportsTransformations(fontEngine)) {
3042 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3045 QPaintEngineEx::drawStaticTextItem(textItem);
3052 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3054 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3055 QRasterPaintEngineState *s = state();
3057 #ifdef QT_DEBUG_DRAW
3058 Q_D(QRasterPaintEngine);
3059 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3060 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3067 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3069 if (!supportsTransformations(ti.fontEngine)) {
3070 QVarLengthArray<QFixedPoint> positions;
3071 QVarLengthArray<glyph_t> glyphs;
3073 QTransform matrix = s->matrix;
3074 matrix.translate(p.x(), p.y());
3076 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3078 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3082 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3083 if (s->matrix.type() <= QTransform::TxTranslate
3084 || (s->matrix.type() == QTransform::TxScale
3085 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3086 drawGlyphsS60(p, ti);
3089 #else // Q_WS_WIN || Q_WS_MAC
3091 QFontEngine *fontEngine = ti.fontEngine;
3093 #if defined(Q_WS_QWS)
3094 if (fontEngine->type() == QFontEngine::Box) {
3095 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3099 if (s->matrix.type() < QTransform::TxScale
3100 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3101 || (fontEngine->type() == QFontEngine::Proxy
3102 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3104 fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3110 if (s->matrix.type() < QTransform::TxScale) {
3112 QVarLengthArray<QFixedPoint> positions;
3113 QVarLengthArray<glyph_t> glyphs;
3114 QTransform matrix = state()->transform();
3116 qreal _x = qFloor(p.x());
3117 qreal _y = qFloor(p.y());
3118 matrix.translate(_x, _y);
3120 fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3121 if (glyphs.size() == 0)
3124 for(int i = 0; i < glyphs.size(); i++) {
3125 QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3126 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3127 // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3128 alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3129 qRound(positions[i].x + metrics.x),
3130 qRound(positions[i].y + metrics.y),
3131 img.width(), img.height());
3137 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3139 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3140 if (fontEngine->type() == QFontEngine::QPF2) {
3141 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3142 if (renderingEngine)
3143 fontEngine = renderingEngine;
3147 if (fontEngine->type() != QFontEngine::Freetype) {
3148 QPaintEngineEx::drawTextItem(p, ti);
3152 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3154 QTransform matrix = s->matrix;
3155 matrix.translate(p.x(), p.y());
3157 QVarLengthArray<QFixedPoint> positions;
3158 QVarLengthArray<glyph_t> glyphs;
3159 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3160 if (glyphs.size() == 0)
3163 if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3164 QPaintEngine::drawTextItem(p, ti);
3170 QPaintEngineEx::drawTextItem(p, ti);
3176 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3178 Q_D(QRasterPaintEngine);
3179 QRasterPaintEngineState *s = state();
3182 if (!s->penData.blend)
3185 if (!s->flags.fast_pen) {
3186 QPaintEngineEx::drawPoints(points, pointCount);
3190 QCosmeticStroker stroker(s, d->deviceRect);
3191 stroker.drawPoints(points, pointCount);
3195 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3197 Q_D(QRasterPaintEngine);
3198 QRasterPaintEngineState *s = state();
3201 if (!s->penData.blend)
3204 if (!s->flags.fast_pen) {
3205 QPaintEngineEx::drawPoints(points, pointCount);
3209 QCosmeticStroker stroker(s, d->deviceRect);
3210 stroker.drawPoints(points, pointCount);
3216 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3218 #ifdef QT_DEBUG_DRAW
3219 qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3221 Q_D(QRasterPaintEngine);
3222 QRasterPaintEngineState *s = state();
3225 if (!s->penData.blend)
3228 if (s->flags.fast_pen) {
3229 QCosmeticStroker stroker(s, d->deviceRect);
3230 for (int i=0; i<lineCount; ++i) {
3231 const QLine &l = lines[i];
3232 stroker.drawLine(l.p1(), l.p2());
3235 QPaintEngineEx::drawLines(lines, lineCount);
3239 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3245 Q_Q(QRasterPaintEngine);
3246 QRasterPaintEngineState *s = q->state();
3248 const QPen &pen = s->lastPen;
3249 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3250 const QVector<qreal> pattern = pen.dashPattern();
3252 qreal patternLength = 0;
3253 for (int i = 0; i < pattern.size(); ++i)
3254 patternLength += pattern.at(i);
3256 if (patternLength <= 0)
3259 qreal length = line.length();
3260 Q_ASSERT(length > 0);
3261 while (length > 0) {
3262 const bool rasterize = *inDash;
3263 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3266 if (dash >= length) {
3268 *dashOffset += dash / width;
3272 *inDash = !(*inDash);
3273 if (++*dashIndex >= pattern.size())
3280 if (rasterize && dash > 0)
3281 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3288 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3290 #ifdef QT_DEBUG_DRAW
3291 qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3293 Q_D(QRasterPaintEngine);
3294 QRasterPaintEngineState *s = state();
3297 if (!s->penData.blend)
3299 if (s->flags.fast_pen) {
3300 QCosmeticStroker stroker(s, d->deviceRect);
3301 for (int i=0; i<lineCount; ++i) {
3302 QLineF line = lines[i];
3303 stroker.drawLine(line.p1(), line.p2());
3306 QPaintEngineEx::drawLines(lines, lineCount);
3314 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3316 QPaintEngineEx::drawEllipse(rect);
3323 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3325 Q_D(QRasterPaintEngine);
3332 CGContextRef QRasterPaintEngine::getCGContext() const
3334 Q_D(const QRasterPaintEngine);
3335 return d->cgContext;
3343 void QRasterPaintEngine::setDC(HDC hdc) {
3344 Q_D(QRasterPaintEngine);
3351 HDC QRasterPaintEngine::getDC() const
3353 Q_D(const QRasterPaintEngine);
3360 void QRasterPaintEngine::releaseDC(HDC) const
3366 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3368 const QTransform &m = state()->matrix;
3369 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3370 QFontEngine::Type fontEngineType = fontEngine->type();
3371 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3372 || (m.type() <= QTransform::TxTranslate
3373 && (fontEngineType == QFontEngine::TestFontEngine
3374 || fontEngineType == QFontEngine::Box))) {
3378 return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3381 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3383 #if defined(Q_WS_MAC)
3384 // Mac font engines don't support scaling and rotation
3385 if (m.type() > QTransform::TxTranslate)
3387 if (m.type() >= QTransform::TxProject)
3391 if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3400 QPoint QRasterPaintEngine::coordinateOffset() const
3402 return QPoint(0, 0);
3406 Draws the given color \a spans with the specified \a color. The \a
3407 count parameter specifies the number of spans.
3409 The default implementation does nothing; reimplement this function
3410 to draw the given color \a spans with the specified \a color. Note
3411 that this function \e must be reimplemented if the framebuffer is
3414 \sa drawBufferSpan()
3416 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3417 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3422 qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3423 "a non memory-mapped device");
3427 \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3429 Draws the given \a buffer.
3431 The default implementation does nothing; reimplement this function
3432 to draw a buffer that contains more than one color. Note that this
3433 function \e must be reimplemented if the framebuffer is not
3436 The \a size parameter specifies the total size of the given \a
3437 buffer, while the \a length parameter specifies the number of
3438 pixels to draw. The buffer's position is given by (\a x, \a
3439 y). The provided \a alpha value is added to each pixel in the
3440 buffer when drawing.
3442 \sa drawColorSpans()
3444 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3445 int x, int y, int length, uint const_alpha)
3452 Q_UNUSED(const_alpha);
3453 qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3454 "a non memory-mapped device");
3458 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3463 Q_D(QRasterPaintEngine);
3465 Q_ASSERT(image.depth() == 1);
3467 const int spanCount = 256;
3468 QT_FT_Span spans[spanCount];
3472 int w = image.width();
3473 int h = image.height();
3474 int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3475 int ymin = qMax(qRound(pos.y()), 0);
3476 int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3477 int xmin = qMax(qRound(pos.x()), 0);
3479 int x_offset = xmin - qRound(pos.x());
3481 QImage::Format format = image.format();
3482 for (int y = ymin; y < ymax; ++y) {
3483 const uchar *src = image.scanLine(y - qRound(pos.y()));
3484 if (format == QImage::Format_MonoLSB) {
3485 for (int x = 0; x < xmax - xmin; ++x) {
3486 int src_x = x + x_offset;
3487 uchar pixel = src[src_x >> 3];
3492 if (pixel & (0x1 << (src_x & 7))) {
3493 spans[n].x = xmin + x;
3495 spans[n].coverage = 255;
3497 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3501 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3504 if (n == spanCount) {
3505 fg->blend(n, spans, fg);
3511 for (int x = 0; x < xmax - xmin; ++x) {
3512 int src_x = x + x_offset;
3513 uchar pixel = src[src_x >> 3];
3518 if (pixel & (0x80 >> (x & 7))) {
3519 spans[n].x = xmin + x;
3521 spans[n].coverage = 255;
3523 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3527 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3530 if (n == spanCount) {
3531 fg->blend(n, spans, fg);
3539 fg->blend(n, spans, fg);
3545 \enum QRasterPaintEngine::ClipType
3548 \value RectClip Indicates that the currently set clip is a single rectangle.
3549 \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3554 Returns the type of the clip currently set.
3556 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3558 Q_D(const QRasterPaintEngine);
3560 const QClipData *clip = d->clip();
3561 if (!clip || clip->hasRectClip)
3569 Returns the bounding rect of the currently set clip.
3571 QRect QRasterPaintEngine::clipBoundingRect() const
3573 Q_D(const QRasterPaintEngine);
3575 const QClipData *clip = d->clip();
3578 return d->deviceRect;
3580 if (clip->hasRectClip)
3581 return clip->clipRect;
3583 return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3586 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3588 Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3590 QVarLengthArray<short, 4096> buffer;
3592 QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3593 QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3594 result->initialize();
3596 for (int y = 0; y < c1->clipSpanHeight; ++y) {
3597 const QSpan *c1_spans = c1ClipLines[y].spans;
3598 int c1_count = c1ClipLines[y].count;
3599 const QSpan *c2_spans = c2ClipLines[y].spans;
3600 int c2_count = c2ClipLines[y].count;
3602 if (c1_count == 0 && c2_count == 0)
3604 if (c1_count == 0) {
3605 result->appendSpans(c2_spans, c2_count);
3607 } else if (c2_count == 0) {
3608 result->appendSpans(c1_spans, c1_count);
3612 // we need to merge the two
3614 // find required length
3615 int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3616 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3618 memset(buffer.data(), 0, buffer.size() * sizeof(short));
3620 // Fill with old spans.
3621 for (int i = 0; i < c1_count; ++i) {
3622 const QSpan *cs = c1_spans + i;
3623 for (int j=cs->x; j<cs->x + cs->len; ++j)
3624 buffer[j] = cs->coverage;
3627 // Fill with new spans
3628 for (int i = 0; i < c2_count; ++i) {
3629 const QSpan *cs = c2_spans + i;
3630 for (int j = cs->x; j < cs->x + cs->len; ++j) {
3631 buffer[j] += cs->coverage;
3632 if (buffer[j] > 255)
3640 // Skip to next span
3641 while (x < max && buffer[x] == 0) ++x;
3642 if (x >= max) break;
3645 int coverage = buffer[x];
3647 // Find length of span
3648 while (x < max && buffer[x] == coverage)
3651 result->appendSpan(sx, x - sx, y, coverage);
3656 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3658 Q_Q(QRasterPaintEngine);
3659 QRasterPaintEngineState *s = q->state();
3661 rasterizer->setAntialiased(s->flags.antialiased);
3663 QRect clipRect(deviceRect);
3665 // ### get from optimized rectbased QClipData
3667 const QClipData *c = clip();
3669 const QRect r(QPoint(c->xmin, c->ymin),
3670 QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3671 clipRect = clipRect.intersected(r);
3672 blend = data->blend;
3674 blend = data->unclipped_blend;
3677 rasterizer->setClipRect(clipRect);
3678 rasterizer->initialize(blend, data);
3681 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3682 ProcessSpans callback,
3683 QSpanData *spanData, QRasterBuffer *rasterBuffer)
3685 if (!callback || !outline)
3688 Q_Q(QRasterPaintEngine);
3689 QRasterPaintEngineState *s = q->state();
3691 if (!s->flags.antialiased) {
3692 initializeRasterizer(spanData);
3694 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3698 rasterizer->rasterize(outline, fillRule);
3702 rasterize(outline, callback, (void *)spanData, rasterBuffer);
3706 int q_gray_rendered_spans(QT_FT_Raster raster);
3709 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3710 ProcessSpans callback,
3711 void *userData, QRasterBuffer *)
3713 if (!callback || !outline)
3716 Q_Q(QRasterPaintEngine);
3717 QRasterPaintEngineState *s = q->state();
3719 if (!s->flags.antialiased) {
3720 rasterizer->setAntialiased(s->flags.antialiased);
3721 rasterizer->setClipRect(deviceRect);
3722 rasterizer->initialize(callback, userData);
3724 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3728 rasterizer->rasterize(outline, fillRule);
3732 // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3733 // minimize memory reallocations. However if initial size for
3734 // raster pool is changed for lower value, reallocations will
3736 const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3737 int rasterPoolSize = rasterPoolInitialSize;
3738 unsigned char *rasterPoolBase;
3739 #if defined(Q_WS_WIN64)
3741 // We make use of setjmp and longjmp in qgrayraster.c which requires
3742 // 16-byte alignment, hence we hardcode this requirement here..
3743 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3745 unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3746 rasterPoolBase = rasterPoolOnStack;
3748 Q_CHECK_PTR(rasterPoolBase);
3750 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3752 void *data = userData;
3754 QT_FT_BBox clip_box = { deviceRect.x(),
3756 deviceRect.x() + deviceRect.width(),
3757 deviceRect.y() + deviceRect.height() };
3759 QT_FT_Raster_Params rasterParams;
3760 rasterParams.target = 0;
3761 rasterParams.source = outline;
3762 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3763 rasterParams.gray_spans = 0;
3764 rasterParams.black_spans = 0;
3765 rasterParams.bit_test = 0;
3766 rasterParams.bit_set = 0;
3767 rasterParams.user = data;
3768 rasterParams.clip_box = clip_box;
3773 int rendered_spans = 0;
3777 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3778 rasterParams.gray_spans = callback;
3779 rasterParams.skip_spans = rendered_spans;
3780 error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3782 // Out of memory, reallocate some more and try again...
3783 if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3784 int new_size = rasterPoolSize * 2;
3785 if (new_size > 1024 * 1024) {
3786 qWarning("QPainter: Rasterization of primitive failed");
3790 rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3792 #if defined(Q_WS_WIN64)
3793 _aligned_free(rasterPoolBase);
3795 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3796 free(rasterPoolBase);
3799 rasterPoolSize = new_size;
3801 #if defined(Q_WS_WIN64)
3802 // We make use of setjmp and longjmp in qgrayraster.c which requires
3803 // 16-byte alignment, hence we hardcode this requirement here..
3804 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3806 (unsigned char *) malloc(rasterPoolSize);
3808 Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3810 qt_ft_grays_raster.raster_done(*grayRaster.data());
3811 qt_ft_grays_raster.raster_new(grayRaster.data());
3812 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3818 #if defined(Q_WS_WIN64)
3819 _aligned_free(rasterPoolBase);
3821 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3822 free(rasterPoolBase);
3826 void QRasterPaintEnginePrivate::recalculateFastImages()
3828 Q_Q(QRasterPaintEngine);
3829 QRasterPaintEngineState *s = q->state();
3831 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3832 && s->matrix.type() <= QTransform::TxShear;
3835 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3837 Q_Q(const QRasterPaintEngine);
3838 const QRasterPaintEngineState *s = q->state();
3840 return s->flags.fast_images
3841 && (mode == QPainter::CompositionMode_SourceOver
3842 || (mode == QPainter::CompositionMode_Source
3843 && !image.hasAlphaChannel()));
3846 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3848 Q_ASSERT(image.depth() == 1);
3850 QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3851 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3853 QRgb fg = PREMUL(color.rgba());
3856 int height = sourceImage.height();
3857 int width = sourceImage.width();
3858 for (int y=0; y<height; ++y) {
3859 uchar *source = sourceImage.scanLine(y);
3860 QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3861 if (!source || !target)
3862 QT_THROW(std::bad_alloc()); // we must have run out of memory
3863 for (int x=0; x < width; ++x)
3864 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3869 QRasterBuffer::~QRasterBuffer()
3873 void QRasterBuffer::init()
3875 compositionMode = QPainter::CompositionMode_SourceOver;
3876 monoDestinationWithClut = false;
3881 QImage::Format QRasterBuffer::prepare(QImage *image)
3883 m_buffer = (uchar *)image->bits();
3884 m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3885 m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3886 bytes_per_pixel = image->depth()/8;
3887 bytes_per_line = image->bytesPerLine();
3889 format = image->format();
3890 drawHelper = qDrawHelper + format;
3891 if (image->depth() == 1 && image->colorTable().size() == 2) {
3892 monoDestinationWithClut = true;
3893 destColor0 = PREMUL(image->colorTable()[0]);
3894 destColor1 = PREMUL(image->colorTable()[1]);
3900 void QRasterBuffer::resetBuffer(int val)
3902 memset(m_buffer, val, m_height*bytes_per_line);
3906 #if defined(Q_WS_QWS)
3907 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3909 m_buffer = reinterpret_cast<uchar*>(device->memory());
3910 m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3911 m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3912 bytes_per_pixel = device->depth() / 8;
3913 bytes_per_line = device->bytesPerLine();
3914 format = device->format();
3915 #ifndef QT_NO_RASTERCALLBACKS
3917 drawHelper = qDrawHelperCallback + format;
3920 drawHelper = qDrawHelper + format;
3923 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3927 return widget->frameGeometry().width();
3929 return widget->frameGeometry().height();
3934 return qt_paint_device_metric(widget, m);
3937 int QCustomRasterPaintDevice::bytesPerLine() const
3939 return (width() * depth() + 7) / 8;
3942 #elif defined(Q_OS_SYMBIAN)
3944 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3948 #endif // Q_OS_SYMBIAN
3951 \class QCustomRasterPaintDevice
3956 \brief The QCustomRasterPaintDevice class is provided to activate
3957 hardware accelerated paint engines in Qt for Embedded Linux.
3959 Note that this class is only available in \l{Qt for Embedded Linux}.
3961 In \l{Qt for Embedded Linux}, painting is a pure software
3962 implementation. But starting with Qt 4.2, it is
3963 possible to add an accelerated graphics driver to take advantage
3964 of available hardware resources.
3966 Hardware acceleration is accomplished by creating a custom screen
3967 driver, accelerating the copying from memory to the screen, and
3968 implementing a custom paint engine accelerating the various
3969 painting operations. Then a custom paint device (derived from the
3970 QCustomRasterPaintDevice class) and a custom window surface
3971 (derived from QWSWindowSurface) must be implemented to make
3972 \l{Qt for Embedded Linux} aware of the accelerated driver.
3974 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3975 documentation for details.
3977 \sa QRasterPaintEngine, QPaintDevice
3981 \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3983 Constructs a custom raster based paint device for the given
3984 top-level \a widget.
3988 \fn int QCustomRasterPaintDevice::bytesPerLine() const
3990 Returns the number of bytes per line in the framebuffer. Note that
3991 this number might be larger than the framebuffer width.
3995 \fn int QCustomRasterPaintDevice::devType() const
4000 \fn QImage::Format QCustomRasterPaintDevice::format() const
4002 Returns the format of the device's memory buffet.
4004 The default format is QImage::Format_ARGB32_Premultiplied. The
4005 only other valid format is QImage::Format_RGB16.
4009 \fn void * QCustomRasterPaintDevice::memory () const
4011 Returns a pointer to the paint device's memory buffer, or 0 if no
4016 \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4021 \fn QSize QCustomRasterPaintDevice::size () const
4026 QClipData::QClipData(int height)
4028 clipSpanHeight = height;
4033 xmin = xmax = ymin = ymax = 0;
4037 hasRectClip = hasRegionClip = false;
4040 QClipData::~QClipData()
4048 void QClipData::initialize()
4054 m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4056 Q_CHECK_PTR(m_clipLines);
4058 m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4059 allocated = clipSpanHeight;
4060 Q_CHECK_PTR(m_spans);
4066 m_clipLines[y].spans = 0;
4067 m_clipLines[y].count = 0;
4071 const int len = clipRect.width();
4074 QSpan *span = m_spans + count;
4078 span->coverage = 255;
4081 m_clipLines[y].spans = span;
4082 m_clipLines[y].count = 1;
4086 while (y < clipSpanHeight) {
4087 m_clipLines[y].spans = 0;
4088 m_clipLines[y].count = 0;
4091 } else if (hasRegionClip) {
4093 const QVector<QRect> rects = clipRegion.rects();
4094 const int numRects = rects.size();
4097 const int maxSpans = (ymax - ymin) * numRects;
4098 if (maxSpans > allocated) {
4099 m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4100 allocated = maxSpans;
4105 int firstInBand = 0;
4107 while (firstInBand < numRects) {
4108 const int currMinY = rects.at(firstInBand).y();
4109 const int currMaxY = currMinY + rects.at(firstInBand).height();
4111 while (y < currMinY) {
4112 m_clipLines[y].spans = 0;
4113 m_clipLines[y].count = 0;
4117 int lastInBand = firstInBand;
4118 while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4121 while (y < currMaxY) {
4123 m_clipLines[y].spans = m_spans + count;
4124 m_clipLines[y].count = lastInBand - firstInBand + 1;
4126 for (int r = firstInBand; r <= lastInBand; ++r) {
4127 const QRect &currRect = rects.at(r);
4128 QSpan *span = m_spans + count;
4129 span->x = currRect.x();
4130 span->len = currRect.width();
4132 span->coverage = 255;
4138 firstInBand = lastInBand + 1;
4141 Q_ASSERT(count <= allocated);
4143 while (y < clipSpanHeight) {
4144 m_clipLines[y].spans = 0;
4145 m_clipLines[y].count = 0;
4151 free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4156 free(m_clipLines); // same for clipLines
4162 void QClipData::fixup()
4167 ymin = ymax = xmin = xmax = 0;
4172 ymin = m_spans[0].y;
4173 ymax = m_spans[count-1].y + 1;
4177 const int firstLeft = m_spans[0].x;
4178 const int firstRight = m_spans[0].x + m_spans[0].len;
4181 for (int i = 0; i < count; ++i) {
4182 QT_FT_Span_& span = m_spans[i];
4185 if (span.y != y + 1 && y != -1)
4188 m_clipLines[y].spans = &span;
4189 m_clipLines[y].count = 1;
4191 ++m_clipLines[y].count;
4193 const int spanLeft = span.x;
4194 const int spanRight = spanLeft + span.len;
4196 if (spanLeft < xmin)
4199 if (spanRight > xmax)
4202 if (spanLeft != firstLeft || spanRight != firstRight)
4208 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4213 Convert \a rect to clip spans.
4215 void QClipData::setClipRect(const QRect &rect)
4217 if (hasRectClip && rect == clipRect)
4220 // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4222 hasRegionClip = false;
4226 xmax = rect.x() + rect.width();
4227 ymin = qMin(rect.y(), clipSpanHeight);
4228 ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4235 // qDebug() << xmin << xmax << ymin << ymax;
4239 Convert \a region to clip spans.
4241 void QClipData::setClipRegion(const QRegion ®ion)
4243 if (region.rectCount() == 1) {
4244 setClipRect(region.rects().at(0));
4248 hasRegionClip = true;
4249 hasRectClip = false;
4250 clipRegion = region;
4252 { // set bounding rect
4253 const QRect rect = region.boundingRect();
4255 xmax = rect.x() + rect.width();
4257 ymax = rect.y() + rect.height();
4269 spans must be sorted on y
4271 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4272 const QSpan *spans, const QSpan *end,
4273 QSpan **outSpans, int available)
4275 const_cast<QClipData *>(clip)->initialize();
4277 QSpan *out = *outSpans;
4279 const QSpan *clipSpans = clip->m_spans + *currentClip;
4280 const QSpan *clipEnd = clip->m_spans + clip->count;
4282 while (available && spans < end ) {
4283 if (clipSpans >= clipEnd) {
4287 if (clipSpans->y > spans->y) {
4291 if (spans->y != clipSpans->y) {
4292 if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4293 clipSpans = clip->m_clipLines[spans->y].spans;
4298 Q_ASSERT(spans->y == clipSpans->y);
4301 int sx2 = sx1 + spans->len;
4302 int cx1 = clipSpans->x;
4303 int cx2 = cx1 + clipSpans->len;
4305 if (cx1 < sx1 && cx2 < sx1) {
4308 } else if (sx1 < cx1 && sx2 < cx1) {
4312 int x = qMax(sx1, cx1);
4313 int len = qMin(sx2, cx2) - x;
4315 out->x = qMax(sx1, cx1);
4316 out->len = qMin(sx2, cx2) - out->x;
4318 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4330 *currentClip = clipSpans - clip->m_spans;
4334 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4336 // qDebug() << "qt_span_fill_clipped" << spanCount;
4337 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4339 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4341 const int NSPANS = 256;
4342 QSpan cspans[NSPANS];
4343 int currentClip = 0;
4344 const QSpan *end = spans + spanCount;
4345 while (spans < end) {
4346 QSpan *clipped = cspans;
4347 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4348 // qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4349 // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4351 if (clipped - cspans)
4352 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4358 Clip spans to \a{clip}-rectangle.
4359 Returns number of unclipped spans
4361 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4364 const short minx = clip.left();
4365 const short miny = clip.top();
4366 const short maxx = clip.right();
4367 const short maxy = clip.bottom();
4370 for (int i = 0; i < numSpans; ++i) {
4371 if (spans[i].y > maxy)
4373 if (spans[i].y < miny
4374 || spans[i].x > maxx
4375 || spans[i].x + spans[i].len <= minx) {
4378 if (spans[i].x < minx) {
4379 spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4382 spans[n].x = spans[i].x;
4383 spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4385 if (spans[n].len == 0)
4387 spans[n].y = spans[i].y;
4388 spans[n].coverage = spans[i].coverage;
4395 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4398 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4399 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4401 Q_ASSERT(fillData->clip);
4402 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4404 // hw: check if this const_cast<> is safe!!!
4405 count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4406 fillData->clip->clipRect);
4408 fillData->unclipped_blend(count, spans, fillData);
4411 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4413 ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4415 // qDebug() << " qt_span_clip: " << count << clipData->operation;
4416 // for (int i = 0; i < qMin(count, 10); ++i) {
4417 // qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4420 switch (clipData->operation) {
4422 case Qt::IntersectClip:
4424 QClipData *newClip = clipData->newClip;
4425 newClip->initialize();
4427 int currentClip = 0;
4428 const QSpan *end = spans + count;
4429 while (spans < end) {
4430 QSpan *newspans = newClip->m_spans + newClip->count;
4431 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4432 &newspans, newClip->allocated - newClip->count);
4433 newClip->count = newspans - newClip->m_spans;
4435 newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4436 newClip->allocated *= 2;
4443 case Qt::ReplaceClip:
4444 clipData->newClip->appendSpans(spans, count);
4452 QImage QRasterBuffer::bufferImage() const
4454 QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4456 for (int y = 0; y < m_height; ++y) {
4457 uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4459 for (int x=0; x<m_width; ++x) {
4460 uint argb = span[x];
4461 image.setPixel(x, y, argb);
4469 void QRasterBuffer::flushToARGBImage(QImage *target) const
4471 int w = qMin(m_width, target->width());
4472 int h = qMin(m_height, target->height());
4474 for (int y=0; y<h; ++y) {
4475 uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4476 QRgb *dest = (QRgb *) target->scanLine(y);
4477 for (int x=0; x<w; ++x) {
4478 QRgb pixel = sourceLine[x];
4479 int alpha = qAlpha(pixel);
4483 dest[x] = (alpha << 24)
4484 | ((255*qRed(pixel)/alpha) << 16)
4485 | ((255*qGreen(pixel)/alpha) << 8)
4486 | ((255*qBlue(pixel)/alpha) << 0);
4493 class QGradientCache
4497 inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4498 stops(s), opacity(op), interpolationMode(mode) {}
4499 uint buffer[GRADIENT_STOPTABLE_SIZE];
4500 QGradientStops stops;
4502 QGradient::InterpolationMode interpolationMode;
4505 typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4508 inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4509 quint64 hash_val = 0;
4511 QGradientStops stops = gradient.stops();
4512 for (int i = 0; i < stops.size() && i <= 2; i++)
4513 hash_val += stops[i].second.rgba();
4515 QMutexLocker lock(&mutex);
4516 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4518 if (it == cache.constEnd())
4519 return addCacheElement(hash_val, gradient, opacity);
4522 const CacheInfo &cache_info = it.value();
4523 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4524 return cache_info.buffer;
4526 } while (it != cache.constEnd() && it.key() == hash_val);
4527 // an exact match for these stops and opacity was not found, create new cache
4528 return addCacheElement(hash_val, gradient, opacity);
4532 inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4534 inline int maxCacheSize() const { return 60; }
4535 inline void generateGradientColorTable(const QGradient& g,
4537 int size, int opacity) const;
4538 uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4539 if (cache.size() == maxCacheSize()) {
4540 // may remove more than 1, but OK
4541 cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4543 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4544 generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4545 return cache.insert(hash_val, cache_entry).value().buffer;
4548 QGradientColorTableHash cache;
4552 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4554 QGradientStops stops = gradient.stops();
4555 int stopCount = stops.count();
4556 Q_ASSERT(stopCount > 0);
4558 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4560 if (stopCount == 2) {
4561 uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4562 uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4564 qreal first_stop = stops[0].first;
4565 qreal second_stop = stops[1].first;
4567 if (second_stop < first_stop) {
4568 qSwap(first_color, second_color);
4569 qSwap(first_stop, second_stop);
4572 if (colorInterpolation) {
4573 first_color = PREMUL(first_color);
4574 second_color = PREMUL(second_color);
4577 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4578 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4580 uint red_first = qRed(first_color) << 16;
4581 uint green_first = qGreen(first_color) << 16;
4582 uint blue_first = qBlue(first_color) << 16;
4583 uint alpha_first = qAlpha(first_color) << 16;
4585 uint red_second = qRed(second_color) << 16;
4586 uint green_second = qGreen(second_color) << 16;
4587 uint blue_second = qBlue(second_color) << 16;
4588 uint alpha_second = qAlpha(second_color) << 16;
4591 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4592 if (colorInterpolation)
4593 colorTable[i] = first_color;
4595 colorTable[i] = PREMUL(first_color);
4598 if (i < second_index) {
4599 qreal reciprocal = qreal(1) / (second_index - first_index);
4601 int red_delta = qRound(int(red_second - red_first) * reciprocal);
4602 int green_delta = qRound(int(green_second - green_first) * reciprocal);
4603 int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4604 int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4607 red_first += 1 << 15;
4608 green_first += 1 << 15;
4609 blue_first += 1 << 15;
4610 alpha_first += 1 << 15;
4612 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4613 red_first += red_delta;
4614 green_first += green_delta;
4615 blue_first += blue_delta;
4616 alpha_first += alpha_delta;
4618 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4619 | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4621 if (colorInterpolation)
4622 colorTable[i] = color;
4624 colorTable[i] = PREMUL(color);
4628 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4629 if (colorInterpolation)
4630 colorTable[i] = second_color;
4632 colorTable[i] = PREMUL(second_color);
4638 uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4639 if (stopCount == 1) {
4640 current_color = PREMUL(current_color);
4641 for (int i = 0; i < size; ++i)
4642 colorTable[i] = current_color;
4646 // The position where the gradient begins and ends
4647 qreal begin_pos = stops[0].first;
4648 qreal end_pos = stops[stopCount-1].first;
4650 int pos = 0; // The position in the color table.
4653 qreal incr = 1 / qreal(size); // the double increment.
4654 qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4656 // Up to first point
4657 colorTable[pos++] = PREMUL(current_color);
4658 while (dpos <= begin_pos) {
4659 colorTable[pos] = colorTable[pos - 1];
4664 int current_stop = 0; // We always interpolate between current and current + 1.
4666 qreal t; // position between current left and right stops
4667 qreal t_delta; // the t increment per entry in the color table
4669 if (dpos < end_pos) {
4671 while (dpos > stops[current_stop+1].first)
4674 if (current_stop != 0)
4675 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4676 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4678 if (colorInterpolation) {
4679 current_color = PREMUL(current_color);
4680 next_color = PREMUL(next_color);
4683 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4684 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4685 t = (dpos - stops[current_stop].first) * c;
4689 Q_ASSERT(current_stop < stopCount);
4691 int dist = qRound(t);
4692 int idist = 256 - dist;
4694 if (colorInterpolation)
4695 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4697 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4702 if (dpos >= end_pos)
4708 while (dpos > stops[current_stop+skip+1].first)
4712 current_stop += skip;
4714 current_color = next_color;
4716 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4717 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4719 if (colorInterpolation) {
4721 current_color = PREMUL(current_color);
4722 next_color = PREMUL(next_color);
4725 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4726 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4727 t = (dpos - stops[current_stop].first) * c;
4734 current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4735 while (pos < size - 1) {
4736 colorTable[pos] = current_color;
4740 // Make sure the last color stop is represented at the end of the table
4741 colorTable[size - 1] = current_color;
4744 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4747 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4751 rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4756 m11 = m22 = m33 = 1.;
4757 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4758 clip = pe ? pe->d_func()->clip() : 0;
4761 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4763 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4765 Qt::BrushStyle brushStyle = qbrush_style(brush);
4766 switch (brushStyle) {
4767 case Qt::SolidPattern: {
4769 QColor c = qbrush_color(brush);
4770 QRgb rgba = c.rgba();
4771 solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4772 if ((solid.color & 0xff000000) == 0
4773 && compositionMode == QPainter::CompositionMode_SourceOver) {
4779 case Qt::LinearGradientPattern:
4781 type = LinearGradient;
4782 const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4783 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4784 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4785 gradient.spread = g->spread();
4787 QLinearGradientData &linearData = gradient.linear;
4789 linearData.origin.x = g->start().x();
4790 linearData.origin.y = g->start().y();
4791 linearData.end.x = g->finalStop().x();
4792 linearData.end.y = g->finalStop().y();
4796 case Qt::RadialGradientPattern:
4798 type = RadialGradient;
4799 const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4800 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4801 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4802 gradient.spread = g->spread();
4804 QRadialGradientData &radialData = gradient.radial;
4806 QPointF center = g->center();
4807 radialData.center.x = center.x();
4808 radialData.center.y = center.y();
4809 radialData.center.radius = g->centerRadius();
4810 QPointF focal = g->focalPoint();
4811 radialData.focal.x = focal.x();
4812 radialData.focal.y = focal.y();
4813 radialData.focal.radius = g->focalRadius();
4817 case Qt::ConicalGradientPattern:
4819 type = ConicalGradient;
4820 const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4821 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4822 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4823 gradient.spread = QGradient::RepeatSpread;
4825 QConicalGradientData &conicalData = gradient.conical;
4827 QPointF center = g->center();
4828 conicalData.center.x = center.x();
4829 conicalData.center.y = center.y();
4830 conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4834 case Qt::Dense1Pattern:
4835 case Qt::Dense2Pattern:
4836 case Qt::Dense3Pattern:
4837 case Qt::Dense4Pattern:
4838 case Qt::Dense5Pattern:
4839 case Qt::Dense6Pattern:
4840 case Qt::Dense7Pattern:
4841 case Qt::HorPattern:
4842 case Qt::VerPattern:
4843 case Qt::CrossPattern:
4844 case Qt::BDiagPattern:
4845 case Qt::FDiagPattern:
4846 case Qt::DiagCrossPattern:
4849 tempImage = new QImage();
4850 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4851 initTexture(tempImage, alpha, QTextureData::Tiled);
4853 case Qt::TexturePattern:
4856 tempImage = new QImage();
4858 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4859 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4861 *tempImage = brush.textureImage();
4862 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4870 adjustSpanMethods();
4873 void QSpanData::adjustSpanMethods()
4883 unclipped_blend = 0;
4886 unclipped_blend = rasterBuffer->drawHelper->blendColor;
4887 bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4888 alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4889 alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4890 fillRect = rasterBuffer->drawHelper->fillRect;
4892 case LinearGradient:
4893 case RadialGradient:
4894 case ConicalGradient:
4895 unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4899 #ifndef QT_NO_RASTERCALLBACKS
4900 if (!rasterBuffer->buffer())
4901 unclipped_blend = qBlendTextureCallback;
4904 unclipped_blend = qBlendTexture;
4906 unclipped_blend = qBlendTexture;
4908 if (!texture.imageData)
4909 unclipped_blend = 0;
4914 if (!unclipped_blend) {
4917 blend = unclipped_blend;
4918 } else if (clip->hasRectClip) {
4919 blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4921 blend = qt_span_fill_clipped;
4925 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4928 // make sure we round off correctly in qdrawhelper.cpp
4929 delta.translate(1.0 / 65536, 1.0 / 65536);
4931 QTransform inv = (delta * matrix).inverted();
4944 const bool affine = !m13 && !m23;
4945 fast_matrix = affine
4946 && m11 * m11 + m21 * m21 < 1e4
4947 && m12 * m12 + m22 * m22 < 1e4
4951 adjustSpanMethods();
4954 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4956 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4958 const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4959 if (!d || d->height == 0) {
4960 texture.imageData = 0;
4967 texture.bytesPerLine = 0;
4968 texture.format = QImage::Format_Invalid;
4969 texture.colorTable = 0;
4970 texture.hasAlpha = alpha != 256;
4972 texture.imageData = d->data;
4973 texture.width = d->width;
4974 texture.height = d->height;
4976 if (sourceRect.isNull()) {
4979 texture.x2 = texture.width;
4980 texture.y2 = texture.height;
4982 texture.x1 = sourceRect.x();
4983 texture.y1 = sourceRect.y();
4984 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4985 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4988 texture.bytesPerLine = d->bytes_per_line;
4990 texture.format = d->format;
4991 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4992 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4994 texture.const_alpha = alpha;
4995 texture.type = _type;
4997 adjustSpanMethods();
5002 \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
5005 Draws the first \a pointCount points in the buffer \a points
5007 The default implementation converts the first \a pointCount QPoints in \a points
5008 to QPointFs and calls the floating point version of drawPoints.
5012 \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5015 Reimplement this function to draw the largest ellipse that can be
5016 contained within rectangle \a rect.
5019 #ifdef QT_DEBUG_DRAW
5020 void dumpClip(int width, int height, const QClipData *clip)
5022 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5023 clipImg.fill(0xffff0000);
5030 ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5032 for (int i = 0; i < clip->count; ++i) {
5033 const QSpan *span = ((QClipData *) clip)->spans() + i;
5034 for (int j = 0; j < span->len; ++j)
5035 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5036 x0 = qMin(x0, int(span->x));
5037 x1 = qMax(x1, int(span->x + span->len - 1));
5039 y0 = qMin(y0, int(span->y));
5040 y1 = qMax(y1, int(span->y));
5043 static int counter = 0;
5050 fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5051 clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));