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);
2925 const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2927 for (int i=0; i<glyphs.size(); ++i) {
2928 TOpenFontCharMetrics tmetrics;
2929 const TUint8 *glyphBitmapBytes;
2930 TSize glyphBitmapSize;
2931 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2932 const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
2933 const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
2934 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2937 if (matrix.type() == QTransform::TxScale)
2938 fe->setFontScale(1.0);
2942 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2945 * Returns true if the rectangle is completely within the current clip
2946 * state of the paint engine.
2948 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2950 const QClipData *cl = clip();
2952 // inline contains() for performance (we know the rects are normalized)
2953 const QRect &r1 = deviceRect;
2954 return (r.left() >= r1.left() && r.right() <= r1.right()
2955 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2959 if (cl->hasRectClip) {
2960 // currently all painting functions clips to deviceRect internally
2961 if (cl->clipRect == deviceRect)
2964 // inline contains() for performance (we know the rects are normalized)
2965 const QRect &r1 = cl->clipRect;
2966 return (r.left() >= r1.left() && r.right() <= r1.right()
2967 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2969 return qt_region_strictContains(cl->clipRegion, r);
2973 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2976 Q_Q(const QRasterPaintEngine);
2977 const QRasterPaintEngineState *s = q->state();
2978 const QClipData *cl = clip();
2980 QRect r = rect.normalized();
2981 // inline contains() for performance (we know the rects are normalized)
2982 const QRect &r1 = deviceRect;
2983 return (r.left() >= r1.left() && r.right() <= r1.right()
2984 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2988 // currently all painting functions that call this function clip to deviceRect internally
2989 if (cl->hasRectClip && cl->clipRect == deviceRect)
2992 if (s->flags.antialiased)
2995 QRect r = rect.normalized();
2997 r.setX(r.x() - penWidth);
2998 r.setY(r.y() - penWidth);
2999 r.setWidth(r.width() + 2 * penWidth);
3000 r.setHeight(r.height() + 2 * penWidth);
3003 if (cl->hasRectClip) {
3004 // inline contains() for performance (we know the rects are normalized)
3005 const QRect &r1 = cl->clipRect;
3006 return (r.left() >= r1.left() && r.right() <= r1.right()
3007 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3009 return qt_region_strictContains(cl->clipRegion, r);
3013 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3016 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3020 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3021 const QSpanData *data) const
3023 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3027 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3028 const QSpanData *data) const
3030 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3036 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3041 QFontEngine *fontEngine = textItem->fontEngine();
3042 if (!supportsTransformations(fontEngine)) {
3043 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3046 QPaintEngineEx::drawStaticTextItem(textItem);
3053 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3055 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3056 QRasterPaintEngineState *s = state();
3058 #ifdef QT_DEBUG_DRAW
3059 Q_D(QRasterPaintEngine);
3060 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3061 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3068 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3070 if (!supportsTransformations(ti.fontEngine)) {
3071 QVarLengthArray<QFixedPoint> positions;
3072 QVarLengthArray<glyph_t> glyphs;
3074 QTransform matrix = s->matrix;
3075 matrix.translate(p.x(), p.y());
3077 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3079 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3083 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3084 if (s->matrix.type() <= QTransform::TxTranslate
3085 || (s->matrix.type() == QTransform::TxScale
3086 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3087 drawGlyphsS60(p, ti);
3090 #else // Q_WS_WIN || Q_WS_MAC
3092 QFontEngine *fontEngine = ti.fontEngine;
3094 #if defined(Q_WS_QWS)
3095 if (fontEngine->type() == QFontEngine::Box) {
3096 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3100 if (s->matrix.type() < QTransform::TxScale
3101 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3102 || (fontEngine->type() == QFontEngine::Proxy
3103 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3105 fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3111 if (s->matrix.type() < QTransform::TxScale) {
3113 QVarLengthArray<QFixedPoint> positions;
3114 QVarLengthArray<glyph_t> glyphs;
3115 QTransform matrix = state()->transform();
3117 qreal _x = qFloor(p.x());
3118 qreal _y = qFloor(p.y());
3119 matrix.translate(_x, _y);
3121 fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3122 if (glyphs.size() == 0)
3125 for(int i = 0; i < glyphs.size(); i++) {
3126 QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3127 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3128 // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3129 alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3130 qRound(positions[i].x + metrics.x),
3131 qRound(positions[i].y + metrics.y),
3132 img.width(), img.height());
3138 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3140 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3141 if (fontEngine->type() == QFontEngine::QPF2) {
3142 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3143 if (renderingEngine)
3144 fontEngine = renderingEngine;
3148 if (fontEngine->type() != QFontEngine::Freetype) {
3149 QPaintEngineEx::drawTextItem(p, ti);
3153 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3155 QTransform matrix = s->matrix;
3156 matrix.translate(p.x(), p.y());
3158 QVarLengthArray<QFixedPoint> positions;
3159 QVarLengthArray<glyph_t> glyphs;
3160 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3161 if (glyphs.size() == 0)
3164 if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3165 QPaintEngine::drawTextItem(p, ti);
3171 QPaintEngineEx::drawTextItem(p, ti);
3177 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3179 Q_D(QRasterPaintEngine);
3180 QRasterPaintEngineState *s = state();
3183 if (!s->penData.blend)
3186 if (!s->flags.fast_pen) {
3187 QPaintEngineEx::drawPoints(points, pointCount);
3191 QCosmeticStroker stroker(s, d->deviceRect);
3192 stroker.drawPoints(points, pointCount);
3196 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3198 Q_D(QRasterPaintEngine);
3199 QRasterPaintEngineState *s = state();
3202 if (!s->penData.blend)
3205 if (!s->flags.fast_pen) {
3206 QPaintEngineEx::drawPoints(points, pointCount);
3210 QCosmeticStroker stroker(s, d->deviceRect);
3211 stroker.drawPoints(points, pointCount);
3217 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3219 #ifdef QT_DEBUG_DRAW
3220 qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3222 Q_D(QRasterPaintEngine);
3223 QRasterPaintEngineState *s = state();
3226 if (!s->penData.blend)
3229 if (s->flags.fast_pen) {
3230 QCosmeticStroker stroker(s, d->deviceRect);
3231 for (int i=0; i<lineCount; ++i) {
3232 const QLine &l = lines[i];
3233 stroker.drawLine(l.p1(), l.p2());
3236 QPaintEngineEx::drawLines(lines, lineCount);
3240 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3246 Q_Q(QRasterPaintEngine);
3247 QRasterPaintEngineState *s = q->state();
3249 const QPen &pen = s->lastPen;
3250 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3251 const QVector<qreal> pattern = pen.dashPattern();
3253 qreal patternLength = 0;
3254 for (int i = 0; i < pattern.size(); ++i)
3255 patternLength += pattern.at(i);
3257 if (patternLength <= 0)
3260 qreal length = line.length();
3261 Q_ASSERT(length > 0);
3262 while (length > 0) {
3263 const bool rasterize = *inDash;
3264 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3267 if (dash >= length) {
3269 *dashOffset += dash / width;
3273 *inDash = !(*inDash);
3274 if (++*dashIndex >= pattern.size())
3281 if (rasterize && dash > 0)
3282 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3289 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3291 #ifdef QT_DEBUG_DRAW
3292 qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3294 Q_D(QRasterPaintEngine);
3295 QRasterPaintEngineState *s = state();
3298 if (!s->penData.blend)
3300 if (s->flags.fast_pen) {
3301 QCosmeticStroker stroker(s, d->deviceRect);
3302 for (int i=0; i<lineCount; ++i) {
3303 QLineF line = lines[i];
3304 stroker.drawLine(line.p1(), line.p2());
3307 QPaintEngineEx::drawLines(lines, lineCount);
3315 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3317 QPaintEngineEx::drawEllipse(rect);
3324 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3326 Q_D(QRasterPaintEngine);
3333 CGContextRef QRasterPaintEngine::getCGContext() const
3335 Q_D(const QRasterPaintEngine);
3336 return d->cgContext;
3344 void QRasterPaintEngine::setDC(HDC hdc) {
3345 Q_D(QRasterPaintEngine);
3352 HDC QRasterPaintEngine::getDC() const
3354 Q_D(const QRasterPaintEngine);
3361 void QRasterPaintEngine::releaseDC(HDC) const
3367 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3369 const QTransform &m = state()->matrix;
3370 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3371 QFontEngine::Type fontEngineType = fontEngine->type();
3372 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3373 || (m.type() <= QTransform::TxTranslate
3374 && (fontEngineType == QFontEngine::TestFontEngine
3375 || fontEngineType == QFontEngine::Box))) {
3379 return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3382 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3384 #if defined(Q_WS_MAC)
3385 // Mac font engines don't support scaling and rotation
3386 if (m.type() > QTransform::TxTranslate)
3388 if (m.type() >= QTransform::TxProject)
3392 if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3401 QPoint QRasterPaintEngine::coordinateOffset() const
3403 return QPoint(0, 0);
3407 Draws the given color \a spans with the specified \a color. The \a
3408 count parameter specifies the number of spans.
3410 The default implementation does nothing; reimplement this function
3411 to draw the given color \a spans with the specified \a color. Note
3412 that this function \e must be reimplemented if the framebuffer is
3415 \sa drawBufferSpan()
3417 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3418 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3423 qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3424 "a non memory-mapped device");
3428 \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3430 Draws the given \a buffer.
3432 The default implementation does nothing; reimplement this function
3433 to draw a buffer that contains more than one color. Note that this
3434 function \e must be reimplemented if the framebuffer is not
3437 The \a size parameter specifies the total size of the given \a
3438 buffer, while the \a length parameter specifies the number of
3439 pixels to draw. The buffer's position is given by (\a x, \a
3440 y). The provided \a alpha value is added to each pixel in the
3441 buffer when drawing.
3443 \sa drawColorSpans()
3445 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3446 int x, int y, int length, uint const_alpha)
3453 Q_UNUSED(const_alpha);
3454 qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3455 "a non memory-mapped device");
3459 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3464 Q_D(QRasterPaintEngine);
3466 Q_ASSERT(image.depth() == 1);
3468 const int spanCount = 256;
3469 QT_FT_Span spans[spanCount];
3473 int w = image.width();
3474 int h = image.height();
3475 int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3476 int ymin = qMax(qRound(pos.y()), 0);
3477 int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3478 int xmin = qMax(qRound(pos.x()), 0);
3480 int x_offset = xmin - qRound(pos.x());
3482 QImage::Format format = image.format();
3483 for (int y = ymin; y < ymax; ++y) {
3484 const uchar *src = image.scanLine(y - qRound(pos.y()));
3485 if (format == QImage::Format_MonoLSB) {
3486 for (int x = 0; x < xmax - xmin; ++x) {
3487 int src_x = x + x_offset;
3488 uchar pixel = src[src_x >> 3];
3493 if (pixel & (0x1 << (src_x & 7))) {
3494 spans[n].x = xmin + x;
3496 spans[n].coverage = 255;
3498 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3502 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3505 if (n == spanCount) {
3506 fg->blend(n, spans, fg);
3512 for (int x = 0; x < xmax - xmin; ++x) {
3513 int src_x = x + x_offset;
3514 uchar pixel = src[src_x >> 3];
3519 if (pixel & (0x80 >> (x & 7))) {
3520 spans[n].x = xmin + x;
3522 spans[n].coverage = 255;
3524 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3528 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3531 if (n == spanCount) {
3532 fg->blend(n, spans, fg);
3540 fg->blend(n, spans, fg);
3546 \enum QRasterPaintEngine::ClipType
3549 \value RectClip Indicates that the currently set clip is a single rectangle.
3550 \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3555 Returns the type of the clip currently set.
3557 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3559 Q_D(const QRasterPaintEngine);
3561 const QClipData *clip = d->clip();
3562 if (!clip || clip->hasRectClip)
3570 Returns the bounding rect of the currently set clip.
3572 QRect QRasterPaintEngine::clipBoundingRect() const
3574 Q_D(const QRasterPaintEngine);
3576 const QClipData *clip = d->clip();
3579 return d->deviceRect;
3581 if (clip->hasRectClip)
3582 return clip->clipRect;
3584 return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3587 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3589 Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3591 QVarLengthArray<short, 4096> buffer;
3593 QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3594 QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3595 result->initialize();
3597 for (int y = 0; y < c1->clipSpanHeight; ++y) {
3598 const QSpan *c1_spans = c1ClipLines[y].spans;
3599 int c1_count = c1ClipLines[y].count;
3600 const QSpan *c2_spans = c2ClipLines[y].spans;
3601 int c2_count = c2ClipLines[y].count;
3603 if (c1_count == 0 && c2_count == 0)
3605 if (c1_count == 0) {
3606 result->appendSpans(c2_spans, c2_count);
3608 } else if (c2_count == 0) {
3609 result->appendSpans(c1_spans, c1_count);
3613 // we need to merge the two
3615 // find required length
3616 int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3617 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3619 memset(buffer.data(), 0, buffer.size() * sizeof(short));
3621 // Fill with old spans.
3622 for (int i = 0; i < c1_count; ++i) {
3623 const QSpan *cs = c1_spans + i;
3624 for (int j=cs->x; j<cs->x + cs->len; ++j)
3625 buffer[j] = cs->coverage;
3628 // Fill with new spans
3629 for (int i = 0; i < c2_count; ++i) {
3630 const QSpan *cs = c2_spans + i;
3631 for (int j = cs->x; j < cs->x + cs->len; ++j) {
3632 buffer[j] += cs->coverage;
3633 if (buffer[j] > 255)
3641 // Skip to next span
3642 while (x < max && buffer[x] == 0) ++x;
3643 if (x >= max) break;
3646 int coverage = buffer[x];
3648 // Find length of span
3649 while (x < max && buffer[x] == coverage)
3652 result->appendSpan(sx, x - sx, y, coverage);
3657 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3659 Q_Q(QRasterPaintEngine);
3660 QRasterPaintEngineState *s = q->state();
3662 rasterizer->setAntialiased(s->flags.antialiased);
3664 QRect clipRect(deviceRect);
3666 // ### get from optimized rectbased QClipData
3668 const QClipData *c = clip();
3670 const QRect r(QPoint(c->xmin, c->ymin),
3671 QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3672 clipRect = clipRect.intersected(r);
3673 blend = data->blend;
3675 blend = data->unclipped_blend;
3678 rasterizer->setClipRect(clipRect);
3679 rasterizer->initialize(blend, data);
3682 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3683 ProcessSpans callback,
3684 QSpanData *spanData, QRasterBuffer *rasterBuffer)
3686 if (!callback || !outline)
3689 Q_Q(QRasterPaintEngine);
3690 QRasterPaintEngineState *s = q->state();
3692 if (!s->flags.antialiased) {
3693 initializeRasterizer(spanData);
3695 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3699 rasterizer->rasterize(outline, fillRule);
3703 rasterize(outline, callback, (void *)spanData, rasterBuffer);
3707 int q_gray_rendered_spans(QT_FT_Raster raster);
3710 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3711 ProcessSpans callback,
3712 void *userData, QRasterBuffer *)
3714 if (!callback || !outline)
3717 Q_Q(QRasterPaintEngine);
3718 QRasterPaintEngineState *s = q->state();
3720 if (!s->flags.antialiased) {
3721 rasterizer->setAntialiased(s->flags.antialiased);
3722 rasterizer->setClipRect(deviceRect);
3723 rasterizer->initialize(callback, userData);
3725 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3729 rasterizer->rasterize(outline, fillRule);
3733 // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3734 // minimize memory reallocations. However if initial size for
3735 // raster pool is changed for lower value, reallocations will
3737 const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3738 int rasterPoolSize = rasterPoolInitialSize;
3739 unsigned char *rasterPoolBase;
3740 #if defined(Q_WS_WIN64)
3742 // We make use of setjmp and longjmp in qgrayraster.c which requires
3743 // 16-byte alignment, hence we hardcode this requirement here..
3744 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3746 unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3747 rasterPoolBase = rasterPoolOnStack;
3749 Q_CHECK_PTR(rasterPoolBase);
3751 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3753 void *data = userData;
3755 QT_FT_BBox clip_box = { deviceRect.x(),
3757 deviceRect.x() + deviceRect.width(),
3758 deviceRect.y() + deviceRect.height() };
3760 QT_FT_Raster_Params rasterParams;
3761 rasterParams.target = 0;
3762 rasterParams.source = outline;
3763 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3764 rasterParams.gray_spans = 0;
3765 rasterParams.black_spans = 0;
3766 rasterParams.bit_test = 0;
3767 rasterParams.bit_set = 0;
3768 rasterParams.user = data;
3769 rasterParams.clip_box = clip_box;
3774 int rendered_spans = 0;
3778 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3779 rasterParams.gray_spans = callback;
3780 rasterParams.skip_spans = rendered_spans;
3781 error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3783 // Out of memory, reallocate some more and try again...
3784 if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3785 int new_size = rasterPoolSize * 2;
3786 if (new_size > 1024 * 1024) {
3787 qWarning("QPainter: Rasterization of primitive failed");
3791 rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3793 #if defined(Q_WS_WIN64)
3794 _aligned_free(rasterPoolBase);
3796 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3797 free(rasterPoolBase);
3800 rasterPoolSize = new_size;
3802 #if defined(Q_WS_WIN64)
3803 // We make use of setjmp and longjmp in qgrayraster.c which requires
3804 // 16-byte alignment, hence we hardcode this requirement here..
3805 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3807 (unsigned char *) malloc(rasterPoolSize);
3809 Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3811 qt_ft_grays_raster.raster_done(*grayRaster.data());
3812 qt_ft_grays_raster.raster_new(grayRaster.data());
3813 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3819 #if defined(Q_WS_WIN64)
3820 _aligned_free(rasterPoolBase);
3822 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3823 free(rasterPoolBase);
3827 void QRasterPaintEnginePrivate::recalculateFastImages()
3829 Q_Q(QRasterPaintEngine);
3830 QRasterPaintEngineState *s = q->state();
3832 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3833 && s->matrix.type() <= QTransform::TxShear;
3836 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3838 Q_Q(const QRasterPaintEngine);
3839 const QRasterPaintEngineState *s = q->state();
3841 return s->flags.fast_images
3842 && (mode == QPainter::CompositionMode_SourceOver
3843 || (mode == QPainter::CompositionMode_Source
3844 && !image.hasAlphaChannel()));
3847 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3849 Q_ASSERT(image.depth() == 1);
3851 QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3852 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3854 QRgb fg = PREMUL(color.rgba());
3857 int height = sourceImage.height();
3858 int width = sourceImage.width();
3859 for (int y=0; y<height; ++y) {
3860 uchar *source = sourceImage.scanLine(y);
3861 QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3862 if (!source || !target)
3863 QT_THROW(std::bad_alloc()); // we must have run out of memory
3864 for (int x=0; x < width; ++x)
3865 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3870 QRasterBuffer::~QRasterBuffer()
3874 void QRasterBuffer::init()
3876 compositionMode = QPainter::CompositionMode_SourceOver;
3877 monoDestinationWithClut = false;
3882 QImage::Format QRasterBuffer::prepare(QImage *image)
3884 m_buffer = (uchar *)image->bits();
3885 m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3886 m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3887 bytes_per_pixel = image->depth()/8;
3888 bytes_per_line = image->bytesPerLine();
3890 format = image->format();
3891 drawHelper = qDrawHelper + format;
3892 if (image->depth() == 1 && image->colorTable().size() == 2) {
3893 monoDestinationWithClut = true;
3894 destColor0 = PREMUL(image->colorTable()[0]);
3895 destColor1 = PREMUL(image->colorTable()[1]);
3901 void QRasterBuffer::resetBuffer(int val)
3903 memset(m_buffer, val, m_height*bytes_per_line);
3907 #if defined(Q_WS_QWS)
3908 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3910 m_buffer = reinterpret_cast<uchar*>(device->memory());
3911 m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3912 m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3913 bytes_per_pixel = device->depth() / 8;
3914 bytes_per_line = device->bytesPerLine();
3915 format = device->format();
3916 #ifndef QT_NO_RASTERCALLBACKS
3918 drawHelper = qDrawHelperCallback + format;
3921 drawHelper = qDrawHelper + format;
3924 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3928 return widget->frameGeometry().width();
3930 return widget->frameGeometry().height();
3935 return qt_paint_device_metric(widget, m);
3938 int QCustomRasterPaintDevice::bytesPerLine() const
3940 return (width() * depth() + 7) / 8;
3943 #elif defined(Q_OS_SYMBIAN)
3945 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3949 #endif // Q_OS_SYMBIAN
3952 \class QCustomRasterPaintDevice
3957 \brief The QCustomRasterPaintDevice class is provided to activate
3958 hardware accelerated paint engines in Qt for Embedded Linux.
3960 Note that this class is only available in \l{Qt for Embedded Linux}.
3962 In \l{Qt for Embedded Linux}, painting is a pure software
3963 implementation. But starting with Qt 4.2, it is
3964 possible to add an accelerated graphics driver to take advantage
3965 of available hardware resources.
3967 Hardware acceleration is accomplished by creating a custom screen
3968 driver, accelerating the copying from memory to the screen, and
3969 implementing a custom paint engine accelerating the various
3970 painting operations. Then a custom paint device (derived from the
3971 QCustomRasterPaintDevice class) and a custom window surface
3972 (derived from QWSWindowSurface) must be implemented to make
3973 \l{Qt for Embedded Linux} aware of the accelerated driver.
3975 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3976 documentation for details.
3978 \sa QRasterPaintEngine, QPaintDevice
3982 \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3984 Constructs a custom raster based paint device for the given
3985 top-level \a widget.
3989 \fn int QCustomRasterPaintDevice::bytesPerLine() const
3991 Returns the number of bytes per line in the framebuffer. Note that
3992 this number might be larger than the framebuffer width.
3996 \fn int QCustomRasterPaintDevice::devType() const
4001 \fn QImage::Format QCustomRasterPaintDevice::format() const
4003 Returns the format of the device's memory buffet.
4005 The default format is QImage::Format_ARGB32_Premultiplied. The
4006 only other valid format is QImage::Format_RGB16.
4010 \fn void * QCustomRasterPaintDevice::memory () const
4012 Returns a pointer to the paint device's memory buffer, or 0 if no
4017 \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4022 \fn QSize QCustomRasterPaintDevice::size () const
4027 QClipData::QClipData(int height)
4029 clipSpanHeight = height;
4034 xmin = xmax = ymin = ymax = 0;
4038 hasRectClip = hasRegionClip = false;
4041 QClipData::~QClipData()
4049 void QClipData::initialize()
4055 m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4057 Q_CHECK_PTR(m_clipLines);
4059 m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4060 allocated = clipSpanHeight;
4061 Q_CHECK_PTR(m_spans);
4067 m_clipLines[y].spans = 0;
4068 m_clipLines[y].count = 0;
4072 const int len = clipRect.width();
4075 QSpan *span = m_spans + count;
4079 span->coverage = 255;
4082 m_clipLines[y].spans = span;
4083 m_clipLines[y].count = 1;
4087 while (y < clipSpanHeight) {
4088 m_clipLines[y].spans = 0;
4089 m_clipLines[y].count = 0;
4092 } else if (hasRegionClip) {
4094 const QVector<QRect> rects = clipRegion.rects();
4095 const int numRects = rects.size();
4098 const int maxSpans = (ymax - ymin) * numRects;
4099 if (maxSpans > allocated) {
4100 m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4101 allocated = maxSpans;
4106 int firstInBand = 0;
4108 while (firstInBand < numRects) {
4109 const int currMinY = rects.at(firstInBand).y();
4110 const int currMaxY = currMinY + rects.at(firstInBand).height();
4112 while (y < currMinY) {
4113 m_clipLines[y].spans = 0;
4114 m_clipLines[y].count = 0;
4118 int lastInBand = firstInBand;
4119 while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4122 while (y < currMaxY) {
4124 m_clipLines[y].spans = m_spans + count;
4125 m_clipLines[y].count = lastInBand - firstInBand + 1;
4127 for (int r = firstInBand; r <= lastInBand; ++r) {
4128 const QRect &currRect = rects.at(r);
4129 QSpan *span = m_spans + count;
4130 span->x = currRect.x();
4131 span->len = currRect.width();
4133 span->coverage = 255;
4139 firstInBand = lastInBand + 1;
4142 Q_ASSERT(count <= allocated);
4144 while (y < clipSpanHeight) {
4145 m_clipLines[y].spans = 0;
4146 m_clipLines[y].count = 0;
4152 free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4157 free(m_clipLines); // same for clipLines
4163 void QClipData::fixup()
4168 ymin = ymax = xmin = xmax = 0;
4173 ymin = m_spans[0].y;
4174 ymax = m_spans[count-1].y + 1;
4178 const int firstLeft = m_spans[0].x;
4179 const int firstRight = m_spans[0].x + m_spans[0].len;
4182 for (int i = 0; i < count; ++i) {
4183 QT_FT_Span_& span = m_spans[i];
4186 if (span.y != y + 1 && y != -1)
4189 m_clipLines[y].spans = &span;
4190 m_clipLines[y].count = 1;
4192 ++m_clipLines[y].count;
4194 const int spanLeft = span.x;
4195 const int spanRight = spanLeft + span.len;
4197 if (spanLeft < xmin)
4200 if (spanRight > xmax)
4203 if (spanLeft != firstLeft || spanRight != firstRight)
4209 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4214 Convert \a rect to clip spans.
4216 void QClipData::setClipRect(const QRect &rect)
4218 if (hasRectClip && rect == clipRect)
4221 // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4223 hasRegionClip = false;
4227 xmax = rect.x() + rect.width();
4228 ymin = qMin(rect.y(), clipSpanHeight);
4229 ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4236 // qDebug() << xmin << xmax << ymin << ymax;
4240 Convert \a region to clip spans.
4242 void QClipData::setClipRegion(const QRegion ®ion)
4244 if (region.rectCount() == 1) {
4245 setClipRect(region.rects().at(0));
4249 hasRegionClip = true;
4250 hasRectClip = false;
4251 clipRegion = region;
4253 { // set bounding rect
4254 const QRect rect = region.boundingRect();
4256 xmax = rect.x() + rect.width();
4258 ymax = rect.y() + rect.height();
4270 spans must be sorted on y
4272 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4273 const QSpan *spans, const QSpan *end,
4274 QSpan **outSpans, int available)
4276 const_cast<QClipData *>(clip)->initialize();
4278 QSpan *out = *outSpans;
4280 const QSpan *clipSpans = clip->m_spans + *currentClip;
4281 const QSpan *clipEnd = clip->m_spans + clip->count;
4283 while (available && spans < end ) {
4284 if (clipSpans >= clipEnd) {
4288 if (clipSpans->y > spans->y) {
4292 if (spans->y != clipSpans->y) {
4293 if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4294 clipSpans = clip->m_clipLines[spans->y].spans;
4299 Q_ASSERT(spans->y == clipSpans->y);
4302 int sx2 = sx1 + spans->len;
4303 int cx1 = clipSpans->x;
4304 int cx2 = cx1 + clipSpans->len;
4306 if (cx1 < sx1 && cx2 < sx1) {
4309 } else if (sx1 < cx1 && sx2 < cx1) {
4313 int x = qMax(sx1, cx1);
4314 int len = qMin(sx2, cx2) - x;
4316 out->x = qMax(sx1, cx1);
4317 out->len = qMin(sx2, cx2) - out->x;
4319 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4331 *currentClip = clipSpans - clip->m_spans;
4335 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4337 // qDebug() << "qt_span_fill_clipped" << spanCount;
4338 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4340 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4342 const int NSPANS = 256;
4343 QSpan cspans[NSPANS];
4344 int currentClip = 0;
4345 const QSpan *end = spans + spanCount;
4346 while (spans < end) {
4347 QSpan *clipped = cspans;
4348 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4349 // qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4350 // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4352 if (clipped - cspans)
4353 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4359 Clip spans to \a{clip}-rectangle.
4360 Returns number of unclipped spans
4362 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4365 const short minx = clip.left();
4366 const short miny = clip.top();
4367 const short maxx = clip.right();
4368 const short maxy = clip.bottom();
4371 for (int i = 0; i < numSpans; ++i) {
4372 if (spans[i].y > maxy)
4374 if (spans[i].y < miny
4375 || spans[i].x > maxx
4376 || spans[i].x + spans[i].len <= minx) {
4379 if (spans[i].x < minx) {
4380 spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4383 spans[n].x = spans[i].x;
4384 spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4386 if (spans[n].len == 0)
4388 spans[n].y = spans[i].y;
4389 spans[n].coverage = spans[i].coverage;
4396 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4399 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4400 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4402 Q_ASSERT(fillData->clip);
4403 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4405 // hw: check if this const_cast<> is safe!!!
4406 count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4407 fillData->clip->clipRect);
4409 fillData->unclipped_blend(count, spans, fillData);
4412 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4414 ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4416 // qDebug() << " qt_span_clip: " << count << clipData->operation;
4417 // for (int i = 0; i < qMin(count, 10); ++i) {
4418 // qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4421 switch (clipData->operation) {
4423 case Qt::IntersectClip:
4425 QClipData *newClip = clipData->newClip;
4426 newClip->initialize();
4428 int currentClip = 0;
4429 const QSpan *end = spans + count;
4430 while (spans < end) {
4431 QSpan *newspans = newClip->m_spans + newClip->count;
4432 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4433 &newspans, newClip->allocated - newClip->count);
4434 newClip->count = newspans - newClip->m_spans;
4436 newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4437 newClip->allocated *= 2;
4444 case Qt::ReplaceClip:
4445 clipData->newClip->appendSpans(spans, count);
4453 QImage QRasterBuffer::bufferImage() const
4455 QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4457 for (int y = 0; y < m_height; ++y) {
4458 uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4460 for (int x=0; x<m_width; ++x) {
4461 uint argb = span[x];
4462 image.setPixel(x, y, argb);
4470 void QRasterBuffer::flushToARGBImage(QImage *target) const
4472 int w = qMin(m_width, target->width());
4473 int h = qMin(m_height, target->height());
4475 for (int y=0; y<h; ++y) {
4476 uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4477 QRgb *dest = (QRgb *) target->scanLine(y);
4478 for (int x=0; x<w; ++x) {
4479 QRgb pixel = sourceLine[x];
4480 int alpha = qAlpha(pixel);
4484 dest[x] = (alpha << 24)
4485 | ((255*qRed(pixel)/alpha) << 16)
4486 | ((255*qGreen(pixel)/alpha) << 8)
4487 | ((255*qBlue(pixel)/alpha) << 0);
4494 class QGradientCache
4498 inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4499 stops(s), opacity(op), interpolationMode(mode) {}
4500 uint buffer[GRADIENT_STOPTABLE_SIZE];
4501 QGradientStops stops;
4503 QGradient::InterpolationMode interpolationMode;
4506 typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4509 inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4510 quint64 hash_val = 0;
4512 QGradientStops stops = gradient.stops();
4513 for (int i = 0; i < stops.size() && i <= 2; i++)
4514 hash_val += stops[i].second.rgba();
4516 QMutexLocker lock(&mutex);
4517 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4519 if (it == cache.constEnd())
4520 return addCacheElement(hash_val, gradient, opacity);
4523 const CacheInfo &cache_info = it.value();
4524 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4525 return cache_info.buffer;
4527 } while (it != cache.constEnd() && it.key() == hash_val);
4528 // an exact match for these stops and opacity was not found, create new cache
4529 return addCacheElement(hash_val, gradient, opacity);
4533 inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4535 inline int maxCacheSize() const { return 60; }
4536 inline void generateGradientColorTable(const QGradient& g,
4538 int size, int opacity) const;
4539 uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4540 if (cache.size() == maxCacheSize()) {
4541 // may remove more than 1, but OK
4542 cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4544 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4545 generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4546 return cache.insert(hash_val, cache_entry).value().buffer;
4549 QGradientColorTableHash cache;
4553 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4555 QGradientStops stops = gradient.stops();
4556 int stopCount = stops.count();
4557 Q_ASSERT(stopCount > 0);
4559 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4561 if (stopCount == 2) {
4562 uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4563 uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4565 qreal first_stop = stops[0].first;
4566 qreal second_stop = stops[1].first;
4568 if (second_stop < first_stop) {
4569 qSwap(first_color, second_color);
4570 qSwap(first_stop, second_stop);
4573 if (colorInterpolation) {
4574 first_color = PREMUL(first_color);
4575 second_color = PREMUL(second_color);
4578 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4579 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4581 uint red_first = qRed(first_color) << 16;
4582 uint green_first = qGreen(first_color) << 16;
4583 uint blue_first = qBlue(first_color) << 16;
4584 uint alpha_first = qAlpha(first_color) << 16;
4586 uint red_second = qRed(second_color) << 16;
4587 uint green_second = qGreen(second_color) << 16;
4588 uint blue_second = qBlue(second_color) << 16;
4589 uint alpha_second = qAlpha(second_color) << 16;
4592 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4593 if (colorInterpolation)
4594 colorTable[i] = first_color;
4596 colorTable[i] = PREMUL(first_color);
4599 if (i < second_index) {
4600 qreal reciprocal = qreal(1) / (second_index - first_index);
4602 int red_delta = qRound(int(red_second - red_first) * reciprocal);
4603 int green_delta = qRound(int(green_second - green_first) * reciprocal);
4604 int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4605 int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4608 red_first += 1 << 15;
4609 green_first += 1 << 15;
4610 blue_first += 1 << 15;
4611 alpha_first += 1 << 15;
4613 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4614 red_first += red_delta;
4615 green_first += green_delta;
4616 blue_first += blue_delta;
4617 alpha_first += alpha_delta;
4619 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4620 | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4622 if (colorInterpolation)
4623 colorTable[i] = color;
4625 colorTable[i] = PREMUL(color);
4629 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4630 if (colorInterpolation)
4631 colorTable[i] = second_color;
4633 colorTable[i] = PREMUL(second_color);
4639 uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4640 if (stopCount == 1) {
4641 current_color = PREMUL(current_color);
4642 for (int i = 0; i < size; ++i)
4643 colorTable[i] = current_color;
4647 // The position where the gradient begins and ends
4648 qreal begin_pos = stops[0].first;
4649 qreal end_pos = stops[stopCount-1].first;
4651 int pos = 0; // The position in the color table.
4654 qreal incr = 1 / qreal(size); // the double increment.
4655 qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4657 // Up to first point
4658 colorTable[pos++] = PREMUL(current_color);
4659 while (dpos <= begin_pos) {
4660 colorTable[pos] = colorTable[pos - 1];
4665 int current_stop = 0; // We always interpolate between current and current + 1.
4667 qreal t; // position between current left and right stops
4668 qreal t_delta; // the t increment per entry in the color table
4670 if (dpos < end_pos) {
4672 while (dpos > stops[current_stop+1].first)
4675 if (current_stop != 0)
4676 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4677 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4679 if (colorInterpolation) {
4680 current_color = PREMUL(current_color);
4681 next_color = PREMUL(next_color);
4684 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4685 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4686 t = (dpos - stops[current_stop].first) * c;
4690 Q_ASSERT(current_stop < stopCount);
4692 int dist = qRound(t);
4693 int idist = 256 - dist;
4695 if (colorInterpolation)
4696 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4698 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4703 if (dpos >= end_pos)
4709 while (dpos > stops[current_stop+skip+1].first)
4713 current_stop += skip;
4715 current_color = next_color;
4717 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4718 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4720 if (colorInterpolation) {
4722 current_color = PREMUL(current_color);
4723 next_color = PREMUL(next_color);
4726 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4727 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4728 t = (dpos - stops[current_stop].first) * c;
4735 current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4736 while (pos < size - 1) {
4737 colorTable[pos] = current_color;
4741 // Make sure the last color stop is represented at the end of the table
4742 colorTable[size - 1] = current_color;
4745 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4748 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4752 rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4757 m11 = m22 = m33 = 1.;
4758 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4759 clip = pe ? pe->d_func()->clip() : 0;
4762 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4764 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4766 Qt::BrushStyle brushStyle = qbrush_style(brush);
4767 switch (brushStyle) {
4768 case Qt::SolidPattern: {
4770 QColor c = qbrush_color(brush);
4771 QRgb rgba = c.rgba();
4772 solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4773 if ((solid.color & 0xff000000) == 0
4774 && compositionMode == QPainter::CompositionMode_SourceOver) {
4780 case Qt::LinearGradientPattern:
4782 type = LinearGradient;
4783 const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4784 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4785 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4786 gradient.spread = g->spread();
4788 QLinearGradientData &linearData = gradient.linear;
4790 linearData.origin.x = g->start().x();
4791 linearData.origin.y = g->start().y();
4792 linearData.end.x = g->finalStop().x();
4793 linearData.end.y = g->finalStop().y();
4797 case Qt::RadialGradientPattern:
4799 type = RadialGradient;
4800 const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4801 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4802 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4803 gradient.spread = g->spread();
4805 QRadialGradientData &radialData = gradient.radial;
4807 QPointF center = g->center();
4808 radialData.center.x = center.x();
4809 radialData.center.y = center.y();
4810 radialData.center.radius = g->centerRadius();
4811 QPointF focal = g->focalPoint();
4812 radialData.focal.x = focal.x();
4813 radialData.focal.y = focal.y();
4814 radialData.focal.radius = g->focalRadius();
4818 case Qt::ConicalGradientPattern:
4820 type = ConicalGradient;
4821 const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4822 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4823 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4824 gradient.spread = QGradient::RepeatSpread;
4826 QConicalGradientData &conicalData = gradient.conical;
4828 QPointF center = g->center();
4829 conicalData.center.x = center.x();
4830 conicalData.center.y = center.y();
4831 conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4835 case Qt::Dense1Pattern:
4836 case Qt::Dense2Pattern:
4837 case Qt::Dense3Pattern:
4838 case Qt::Dense4Pattern:
4839 case Qt::Dense5Pattern:
4840 case Qt::Dense6Pattern:
4841 case Qt::Dense7Pattern:
4842 case Qt::HorPattern:
4843 case Qt::VerPattern:
4844 case Qt::CrossPattern:
4845 case Qt::BDiagPattern:
4846 case Qt::FDiagPattern:
4847 case Qt::DiagCrossPattern:
4850 tempImage = new QImage();
4851 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4852 initTexture(tempImage, alpha, QTextureData::Tiled);
4854 case Qt::TexturePattern:
4857 tempImage = new QImage();
4859 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4860 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4862 *tempImage = brush.textureImage();
4863 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4871 adjustSpanMethods();
4874 void QSpanData::adjustSpanMethods()
4884 unclipped_blend = 0;
4887 unclipped_blend = rasterBuffer->drawHelper->blendColor;
4888 bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4889 alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4890 alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4891 fillRect = rasterBuffer->drawHelper->fillRect;
4893 case LinearGradient:
4894 case RadialGradient:
4895 case ConicalGradient:
4896 unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4900 #ifndef QT_NO_RASTERCALLBACKS
4901 if (!rasterBuffer->buffer())
4902 unclipped_blend = qBlendTextureCallback;
4905 unclipped_blend = qBlendTexture;
4907 unclipped_blend = qBlendTexture;
4909 if (!texture.imageData)
4910 unclipped_blend = 0;
4915 if (!unclipped_blend) {
4918 blend = unclipped_blend;
4919 } else if (clip->hasRectClip) {
4920 blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4922 blend = qt_span_fill_clipped;
4926 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4929 // make sure we round off correctly in qdrawhelper.cpp
4930 delta.translate(1.0 / 65536, 1.0 / 65536);
4932 QTransform inv = (delta * matrix).inverted();
4945 const bool affine = !m13 && !m23;
4946 fast_matrix = affine
4947 && m11 * m11 + m21 * m21 < 1e4
4948 && m12 * m12 + m22 * m22 < 1e4
4952 adjustSpanMethods();
4955 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4957 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4959 const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4960 if (!d || d->height == 0) {
4961 texture.imageData = 0;
4968 texture.bytesPerLine = 0;
4969 texture.format = QImage::Format_Invalid;
4970 texture.colorTable = 0;
4971 texture.hasAlpha = alpha != 256;
4973 texture.imageData = d->data;
4974 texture.width = d->width;
4975 texture.height = d->height;
4977 if (sourceRect.isNull()) {
4980 texture.x2 = texture.width;
4981 texture.y2 = texture.height;
4983 texture.x1 = sourceRect.x();
4984 texture.y1 = sourceRect.y();
4985 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4986 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4989 texture.bytesPerLine = d->bytes_per_line;
4991 texture.format = d->format;
4992 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4993 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4995 texture.const_alpha = alpha;
4996 texture.type = _type;
4998 adjustSpanMethods();
5003 \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
5006 Draws the first \a pointCount points in the buffer \a points
5008 The default implementation converts the first \a pointCount QPoints in \a points
5009 to QPointFs and calls the floating point version of drawPoints.
5013 \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5016 Reimplement this function to draw the largest ellipse that can be
5017 contained within rectangle \a rect.
5020 #ifdef QT_DEBUG_DRAW
5021 void dumpClip(int width, int height, const QClipData *clip)
5023 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5024 clipImg.fill(0xffff0000);
5031 ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5033 for (int i = 0; i < clip->count; ++i) {
5034 const QSpan *span = ((QClipData *) clip)->spans() + i;
5035 for (int j = 0; j < span->len; ++j)
5036 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5037 x0 = qMin(x0, int(span->x));
5038 x1 = qMax(x1, int(span->x + span->len - 1));
5040 y0 = qMin(y0, int(span->y));
5041 y1 = qMax(y1, int(span->y));
5044 static int counter = 0;
5051 fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5052 clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));