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))
131 extern bool qt_cleartype_enabled;
135 extern bool qt_applefontsmoothing_enabled;
139 /********************************************************************************
142 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
143 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
144 static void qt_span_clip(int count, const QSpan *spans, void *userData);
145 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
151 Qt::ClipOperation operation;
157 LineDrawIncludeLastPixel
160 struct QRasterFloatPoint {
166 static const QRectF boundingRect(const QPointF *points, int pointCount)
168 const QPointF *e = points;
169 const QPointF *last = points + pointCount;
170 qreal minx, maxx, miny, maxy;
171 minx = maxx = e->x();
172 miny = maxy = e->y();
176 else if (e->x() > maxx)
180 else if (e->y() > maxy)
183 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
187 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
188 return (elementCount == 5 // 5-point polygon, check for closed rect
189 && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
190 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
191 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
192 && pts[0] < pts[4] && pts[1] < pts[5]
194 (elementCount == 4 // 4-point polygon, check for unclosed rect
195 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
196 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
197 && pts[0] < pts[4] && pts[1] < pts[5]
202 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
204 ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
207 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
209 ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
212 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
213 qfixed c2x, qfixed c2y,
214 qfixed ex, qfixed ey,
217 ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
218 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
219 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
223 #if !defined(QT_NO_DEBUG) && 0
224 static void qt_debug_path(const QPainterPath &path)
226 const char *names[] = {
233 fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
234 for (int i=0; i<path.elementCount(); ++i) {
235 const QPainterPath::Element &e = path.elementAt(i);
236 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
237 fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
242 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
243 QPaintEngineExPrivate(),
250 \class QRasterPaintEngine
255 \brief The QRasterPaintEngine class enables hardware acceleration
256 of painting operations in Qt for Embedded Linux.
258 Note that this functionality is only available in
259 \l{Qt for Embedded Linux}.
261 In \l{Qt for Embedded Linux}, painting is a pure software
262 implementation. But starting with Qt 4.2, it is
263 possible to add an accelerated graphics driver to take advantage
264 of available hardware resources.
266 Hardware acceleration is accomplished by creating a custom screen
267 driver, accelerating the copying from memory to the screen, and
268 implementing a custom paint engine accelerating the various
269 painting operations. Then a custom paint device (derived from the
270 QCustomRasterPaintDevice class) and a custom window surface
271 (derived from QWSWindowSurface) must be implemented to make
272 \l{Qt for Embedded Linux} aware of the accelerated driver.
274 \note The QRasterPaintEngine class does not support 8-bit images.
275 Instead, they need to be converted to a supported format, such as
276 QImage::Format_ARGB32_Premultiplied.
278 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
279 documentation for details.
281 \sa QCustomRasterPaintDevice, QPaintEngine
285 \fn Type QRasterPaintEngine::type() const
291 \relates QRasterPaintEngine
293 A struct equivalent to QT_FT_Span, containing a position (x,
294 y), the span's length in pixels and its color/coverage (a value
295 ranging from 0 to 255).
301 Creates a raster based paint engine for operating on the given
302 \a device, with the complete set of \l
303 {QPaintEngine::PaintEngineFeature}{paint engine features and
306 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
307 : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
309 d_func()->device = device;
316 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
319 d_func()->device = device;
323 void QRasterPaintEngine::init()
325 Q_D(QRasterPaintEngine);
332 // The antialiasing raster.
333 d->grayRaster.reset(new QT_FT_Raster);
334 Q_CHECK_PTR(d->grayRaster.data());
335 if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
336 QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
339 d->rasterizer.reset(new QRasterizer);
340 d->rasterBuffer.reset(new QRasterBuffer());
341 d->outlineMapper.reset(new QOutlineMapper);
342 d->outlinemapper_xform_dirty = true;
344 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
345 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
346 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
348 d->baseClip.reset(new QClipData(d->device->height()));
349 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
351 d->image_filler.init(d->rasterBuffer.data(), this);
352 d->image_filler.type = QSpanData::Texture;
354 d->image_filler_xform.init(d->rasterBuffer.data(), this);
355 d->image_filler_xform.type = QSpanData::Texture;
357 d->solid_color_filler.init(d->rasterBuffer.data(), this);
358 d->solid_color_filler.type = QSpanData::Solid;
360 d->deviceDepth = d->device->depth();
362 d->mono_surface = false;
363 gccaps &= ~PorterDuff;
365 QImage::Format format = QImage::Format_Invalid;
367 switch (d->device->devType()) {
368 case QInternal::Pixmap:
369 qWarning("QRasterPaintEngine: unsupported for pixmaps...");
371 case QInternal::Image:
372 format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
375 case QInternal::CustomRaster:
376 d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
380 qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
386 case QImage::Format_MonoLSB:
387 case QImage::Format_Mono:
388 d->mono_surface = true;
390 case QImage::Format_ARGB8565_Premultiplied:
391 case QImage::Format_ARGB8555_Premultiplied:
392 case QImage::Format_ARGB6666_Premultiplied:
393 case QImage::Format_ARGB4444_Premultiplied:
394 case QImage::Format_ARGB32_Premultiplied:
395 case QImage::Format_ARGB32:
396 gccaps |= PorterDuff;
398 case QImage::Format_RGB32:
399 case QImage::Format_RGB444:
400 case QImage::Format_RGB555:
401 case QImage::Format_RGB666:
402 case QImage::Format_RGB888:
403 case QImage::Format_RGB16:
414 Destroys this paint engine.
416 QRasterPaintEngine::~QRasterPaintEngine()
418 Q_D(QRasterPaintEngine);
420 qt_ft_grays_raster.raster_done(*d->grayRaster.data());
426 bool QRasterPaintEngine::begin(QPaintDevice *device)
428 Q_D(QRasterPaintEngine);
430 if (device->devType() == QInternal::Pixmap) {
431 QPixmap *pixmap = static_cast<QPixmap *>(device);
432 QPixmapData *pd = pixmap->pixmapData();
433 if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
434 d->device = pd->buffer();
439 // Make sure QPaintEngine::paintDevice() returns the proper device.
442 Q_ASSERT(d->device->devType() == QInternal::Image
443 || d->device->devType() == QInternal::CustomRaster);
445 d->systemStateChanged();
447 QRasterPaintEngineState *s = state();
448 ensureOutlineMapper();
449 d->outlineMapper->m_clip_rect = d->deviceRect;
451 if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
452 d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
453 if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
454 d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
456 d->rasterizer->setClipRect(d->deviceRect);
458 s->penData.init(d->rasterBuffer.data(), this);
459 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
460 s->stroker = &d->basicStroker;
461 d->basicStroker.setClipRect(d->deviceRect);
463 s->brushData.init(d->rasterBuffer.data(), this);
464 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
466 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
468 setDirty(DirtyBrushOrigin);
471 qDebug() << "QRasterPaintEngine::begin(" << (void *) device
472 << ") devType:" << device->devType()
473 << "devRect:" << d->deviceRect;
475 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
479 #if defined(Q_WS_WIN)
480 d->isPlain45DegreeRotation = true;
484 d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
485 #if defined(Q_WS_WIN)
486 else if (qt_cleartype_enabled)
487 #elif defined (Q_WS_MAC)
488 else if (qt_applefontsmoothing_enabled)
493 QImage::Format format = static_cast<QImage *>(d->device)->format();
494 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
495 d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
497 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
499 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
508 bool QRasterPaintEngine::end()
511 Q_D(QRasterPaintEngine);
512 qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
514 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
524 void QRasterPaintEngine::releaseBuffer()
526 Q_D(QRasterPaintEngine);
527 d->rasterBuffer.reset(new QRasterBuffer);
533 QSize QRasterPaintEngine::size() const
535 Q_D(const QRasterPaintEngine);
536 return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
543 void QRasterPaintEngine::saveBuffer(const QString &s) const
545 Q_D(const QRasterPaintEngine);
546 d->rasterBuffer->bufferImage().save(s, "PNG");
553 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
555 QRasterPaintEngineState *s = state();
556 // FALCON: get rid of this line, see drawImage call below.
558 QTransform::TransformationType txop = s->matrix.type();
562 case QTransform::TxNone:
563 s->flags.int_xform = true;
566 case QTransform::TxTranslate:
567 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
568 && qreal(int(s->matrix.dy())) == s->matrix.dy();
571 case QTransform::TxScale:
572 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
573 && qreal(int(s->matrix.dy())) == s->matrix.dy()
574 && qreal(int(s->matrix.m11())) == s->matrix.m11()
575 && qreal(int(s->matrix.m22())) == s->matrix.m22();
578 default: // shear / perspective...
579 s->flags.int_xform = false;
583 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
585 ensureOutlineMapper();
588 Q_D(QRasterPaintEngine);
589 d->isPlain45DegreeRotation = false;
590 if (txop >= QTransform::TxRotate) {
591 d->isPlain45DegreeRotation =
592 (qFuzzyIsNull(matrix.m11())
593 && qFuzzyIsNull(matrix.m12() - qreal(1))
594 && qFuzzyIsNull(matrix.m21() + qreal(1))
595 && qFuzzyIsNull(matrix.m22())
598 (qFuzzyIsNull(matrix.m11() + qreal(1))
599 && qFuzzyIsNull(matrix.m12())
600 && qFuzzyIsNull(matrix.m21())
601 && qFuzzyIsNull(matrix.m22() + qreal(1))
604 (qFuzzyIsNull(matrix.m11())
605 && qFuzzyIsNull(matrix.m12() + qreal(1))
606 && qFuzzyIsNull(matrix.m21() - qreal(1))
607 && qFuzzyIsNull(matrix.m22())
617 QRasterPaintEngineState::~QRasterPaintEngineState()
619 if (flags.has_clip_ownership)
624 QRasterPaintEngineState::QRasterPaintEngineState()
636 flags.fast_pen = true;
637 flags.antialiased = false;
638 flags.bilinear = false;
639 flags.fast_text = true;
640 flags.int_xform = true;
641 flags.tx_noshear = true;
642 flags.fast_images = true;
645 flags.has_clip_ownership = false;
650 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
655 , strokeFlags(s.strokeFlags)
656 , lastBrush(s.lastBrush)
657 , brushData(s.brushData)
658 , fillFlags(s.fillFlags)
659 , pixmapFlags(s.pixmapFlags)
660 , intOpacity(s.intOpacity)
664 , flag_bits(s.flag_bits)
666 brushData.tempImage = 0;
667 penData.tempImage = 0;
668 flags.has_clip_ownership = false;
674 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
676 QRasterPaintEngineState *s;
678 s = new QRasterPaintEngineState();
680 s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
688 void QRasterPaintEngine::setState(QPainterState *s)
690 Q_D(QRasterPaintEngine);
691 QPaintEngineEx::setState(s);
692 d->rasterBuffer->compositionMode = s->composition_mode;
696 \fn QRasterPaintEngineState *QRasterPaintEngine::state()
701 \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
708 void QRasterPaintEngine::penChanged()
711 qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
713 QRasterPaintEngineState *s = state();
714 s->strokeFlags |= DirtyPen;
715 s->dirty |= DirtyPen;
721 void QRasterPaintEngine::updatePen(const QPen &pen)
723 Q_D(QRasterPaintEngine);
724 QRasterPaintEngineState *s = state();
726 qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
729 Qt::PenStyle pen_style = qpen_style(pen);
734 s->penData.clip = d->clip();
735 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
737 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
738 || pen.brush().transform().type() >= QTransform::TxNone) {
739 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
742 // Slightly ugly handling of an uncommon case... We need to change
743 // the pen because it is reused in draw_midpoint to decide dashed
745 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
746 pen_style = Qt::SolidLine;
747 s->lastPen.setStyle(Qt::SolidLine);
750 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
751 d->basicStroker.setCapStyle(qpen_capStyle(pen));
752 d->basicStroker.setMiterLimit(pen.miterLimit());
754 qreal penWidth = qpen_widthf(pen);
756 d->basicStroker.setStrokeWidth(1);
758 d->basicStroker.setStrokeWidth(penWidth);
760 if(pen_style == Qt::SolidLine) {
761 s->stroker = &d->basicStroker;
762 } else if (pen_style != Qt::NoPen) {
764 d->dashStroker.reset(new QDashStroker(&d->basicStroker));
765 if (pen.isCosmetic()) {
766 d->dashStroker->setClipRect(d->deviceRect);
768 // ### I've seen this inverted devrect multiple places now...
769 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
770 d->dashStroker->setClipRect(clipRect);
772 d->dashStroker->setDashPattern(pen.dashPattern());
773 d->dashStroker->setDashOffset(pen.dashOffset());
774 s->stroker = d->dashStroker.data();
779 ensureState(); // needed because of tx_noshear...
780 s->flags.fast_pen = pen_style > Qt::NoPen
782 && ((pen.isCosmetic() && penWidth <= 1)
783 || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
785 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
795 void QRasterPaintEngine::brushOriginChanged()
797 QRasterPaintEngineState *s = state();
799 qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
802 s->fillFlags |= DirtyBrushOrigin;
809 void QRasterPaintEngine::brushChanged()
811 QRasterPaintEngineState *s = state();
813 qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
815 s->fillFlags |= DirtyBrush;
824 void QRasterPaintEngine::updateBrush(const QBrush &brush)
827 qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
829 Q_D(QRasterPaintEngine);
830 QRasterPaintEngineState *s = state();
831 // must set clip prior to setup, as setup uses it...
832 s->brushData.clip = d->clip();
833 s->brushData.setup(brush, s->intOpacity, s->composition_mode);
834 if (s->fillFlags & DirtyTransform
835 || brush.transform().type() >= QTransform::TxNone)
836 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
837 s->lastBrush = brush;
841 void QRasterPaintEngine::updateOutlineMapper()
843 Q_D(QRasterPaintEngine);
844 d->outlineMapper->setMatrix(state()->matrix);
847 void QRasterPaintEngine::updateState()
849 QRasterPaintEngineState *s = state();
851 if (s->dirty & DirtyTransform)
852 updateMatrix(s->matrix);
854 if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
855 const QPainter::CompositionMode mode = s->composition_mode;
856 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
857 && s->intOpacity == 256
858 && (mode == QPainter::CompositionMode_Source
859 || (mode == QPainter::CompositionMode_SourceOver
860 && qAlpha(s->penData.solid.color) == 255));
870 void QRasterPaintEngine::opacityChanged()
872 QRasterPaintEngineState *s = state();
875 qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
878 s->fillFlags |= DirtyOpacity;
879 s->strokeFlags |= DirtyOpacity;
880 s->pixmapFlags |= DirtyOpacity;
881 s->dirty |= DirtyOpacity;
882 s->intOpacity = (int) (s->opacity * 256);
888 void QRasterPaintEngine::compositionModeChanged()
890 Q_D(QRasterPaintEngine);
891 QRasterPaintEngineState *s = state();
894 qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
897 s->fillFlags |= DirtyCompositionMode;
898 s->dirty |= DirtyCompositionMode;
900 s->strokeFlags |= DirtyCompositionMode;
901 d->rasterBuffer->compositionMode = s->composition_mode;
903 d->recalculateFastImages();
909 void QRasterPaintEngine::renderHintsChanged()
911 QRasterPaintEngineState *s = state();
914 qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
917 bool was_aa = s->flags.antialiased;
918 bool was_bilinear = s->flags.bilinear;
920 s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
921 s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
923 if (was_aa != s->flags.antialiased)
924 s->strokeFlags |= DirtyHints;
926 if (was_bilinear != s->flags.bilinear) {
927 s->strokeFlags |= DirtyPen;
928 s->fillFlags |= DirtyBrush;
931 Q_D(QRasterPaintEngine);
932 d->recalculateFastImages();
938 void QRasterPaintEngine::transformChanged()
940 QRasterPaintEngineState *s = state();
943 qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
946 s->fillFlags |= DirtyTransform;
947 s->strokeFlags |= DirtyTransform;
949 s->dirty |= DirtyTransform;
951 Q_D(QRasterPaintEngine);
952 d->recalculateFastImages();
958 void QRasterPaintEngine::clipEnabledChanged()
960 QRasterPaintEngineState *s = state();
963 qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
967 s->clip->enabled = s->clipEnabled;
968 s->fillFlags |= DirtyClipEnabled;
969 s->strokeFlags |= DirtyClipEnabled;
970 s->pixmapFlags |= DirtyClipEnabled;
975 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
977 rasterBuffer->prepare(device);
981 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
983 SrcOverBlendFunc func,
988 if (alpha == 0 || !clip.isValid())
991 Q_ASSERT(img.depth() >= 8);
993 int srcBPL = img.bytesPerLine();
994 const uchar *srcBits = img.bits();
995 int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
996 int iw = img.width();
997 int ih = img.height();
1002 // Adjust the image according to the source offset...
1003 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1006 // adapt the x parameters
1007 int x = qRound(pt.x());
1009 int cx2 = clip.x() + clip.width();
1012 srcBits += srcSize * d;
1017 int d = x + iw - cx2;
1023 // adapt the y paremeters...
1025 int cy2 = clip.y() + clip.height();
1026 int y = qRound(pt.y());
1029 srcBits += srcBPL * d;
1034 int d = y + ih - cy2;
1040 // call the blend function...
1041 int dstSize = rasterBuffer->bytesPerPixel();
1042 int dstBPL = rasterBuffer->bytesPerLine();
1043 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1050 void QRasterPaintEnginePrivate::systemStateChanged()
1052 QRect clipRect(0, 0,
1053 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1054 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1056 if (!systemClip.isEmpty()) {
1057 QRegion clippedDeviceRgn = systemClip & clipRect;
1058 deviceRect = clippedDeviceRgn.boundingRect();
1059 baseClip->setClipRegion(clippedDeviceRgn);
1061 deviceRect = clipRect;
1062 baseClip->setClipRect(deviceRect);
1064 #ifdef QT_DEBUG_DRAW
1065 qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1068 exDeviceRect = deviceRect;
1070 Q_Q(QRasterPaintEngine);
1071 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1072 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1073 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1076 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1078 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1081 Q_Q(QRasterPaintEngine);
1082 bool bilinear = q->state()->flags.bilinear;
1084 if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1085 spanData->setupMatrix(b.transform() * m, bilinear);
1087 if (m.type() <= QTransform::TxTranslate) {
1088 // specialize setupMatrix for translation matrices
1089 // to avoid needless matrix inversion
1097 spanData->dx = -m.dx();
1098 spanData->dy = -m.dy();
1099 spanData->txop = m.type();
1100 spanData->bilinear = bilinear;
1101 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1102 spanData->adjustSpanMethods();
1104 spanData->setupMatrix(m, bilinear);
1109 // #define QT_CLIPPING_RATIOS
1111 #ifdef QT_CLIPPING_RATIOS
1116 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1118 if (d->clip()->hasRectClip)
1120 if (d->clip()->hasRegionClip)
1124 if ((totalClips % 5000) == 0) {
1125 printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1126 rectClips * 100.0 / (qreal) totalClips,
1127 regionClips * 100.0 / (qreal) totalClips,
1128 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1137 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1139 if (s->flags.has_clip_ownership)
1142 s->flags.has_clip_ownership = false;
1145 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1147 s->fillFlags |= QPaintEngine::DirtyClipPath;
1148 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1149 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1151 d->solid_color_filler.clip = d->clip();
1152 d->solid_color_filler.adjustSpanMethods();
1154 #ifdef QT_DEBUG_DRAW
1155 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1164 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1166 #ifdef QT_DEBUG_DRAW
1167 qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1169 if (path.elements()) {
1170 for (int i=0; i<path.elementCount(); ++i) {
1171 qDebug() << " - " << path.elements()[i]
1172 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1175 for (int i=0; i<path.elementCount(); ++i) {
1176 qDebug() << " ---- "
1177 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1182 Q_D(QRasterPaintEngine);
1183 QRasterPaintEngineState *s = state();
1185 const qreal *points = path.points();
1186 const QPainterPath::ElementType *types = path.elements();
1188 // There are some cases that are not supported by clip(QRect)
1189 if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1190 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1191 if (s->matrix.type() <= QTransform::TxScale
1192 && ((path.shape() == QVectorPath::RectangleHint)
1193 || (isRect(points, path.elementCount())
1194 && (!types || (types[0] == QPainterPath::MoveToElement
1195 && types[1] == QPainterPath::LineToElement
1196 && types[2] == QPainterPath::LineToElement
1197 && types[3] == QPainterPath::LineToElement))))) {
1198 #ifdef QT_DEBUG_DRAW
1199 qDebug() << " --- optimizing vector clip to rect clip...";
1202 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1203 if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1208 if (op == Qt::NoClip) {
1209 qrasterpaintengine_state_setNoClip(s);
1212 QClipData *base = d->baseClip.data();
1214 // Intersect with current clip when available...
1215 if (op == Qt::IntersectClip && s->clip)
1218 // We always intersect, except when there is nothing to
1219 // intersect with, in which case we simplify the operation to
1221 Qt::ClipOperation isectOp = Qt::IntersectClip;
1223 isectOp = Qt::ReplaceClip;
1225 QClipData *newClip = new QClipData(d->rasterBuffer->height());
1226 newClip->initialize();
1227 ClipData clipData = { base, newClip, isectOp };
1228 ensureOutlineMapper();
1229 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1233 if (op == Qt::UniteClip) {
1235 QClipData *result = new QClipData(d->rasterBuffer->height());
1236 QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1237 qt_merge_clip(current, newClip, result);
1245 if (s->flags.has_clip_ownership)
1249 s->flags.has_clip_ownership = true;
1251 qrasterpaintengine_dirty_clip(d, s);
1259 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1261 #ifdef QT_DEBUG_DRAW
1262 qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1265 QRasterPaintEngineState *s = state();
1267 if (op == Qt::NoClip) {
1268 qrasterpaintengine_state_setNoClip(s);
1270 } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1271 QPaintEngineEx::clip(rect, op);
1274 } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1275 QPaintEngineEx::clip(rect, op);
1281 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1283 Q_D(QRasterPaintEngine);
1284 QRect clipRect = r & d->deviceRect;
1285 QRasterPaintEngineState *s = state();
1287 if (op == Qt::ReplaceClip || s->clip == 0) {
1289 // No current clip, hence we intersect with sysclip and be
1291 QRegion clipRegion = systemClip();
1292 QClipData *clip = new QClipData(d->rasterBuffer->height());
1294 if (clipRegion.isEmpty())
1295 clip->setClipRect(clipRect);
1297 clip->setClipRegion(clipRegion & clipRect);
1299 if (s->flags.has_clip_ownership)
1303 s->clip->enabled = true;
1304 s->flags.has_clip_ownership = true;
1306 } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1307 QClipData *base = s->clip;
1310 if (base->hasRectClip || base->hasRegionClip) {
1311 if (!s->flags.has_clip_ownership) {
1312 s->clip = new QClipData(d->rasterBuffer->height());
1313 s->flags.has_clip_ownership = true;
1315 if (base->hasRectClip)
1316 s->clip->setClipRect(base->clipRect & clipRect);
1318 s->clip->setClipRegion(base->clipRegion & clipRect);
1319 s->clip->enabled = true;
1327 qrasterpaintengine_dirty_clip(d, s);
1335 void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
1337 #ifdef QT_DEBUG_DRAW
1338 qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1341 Q_D(QRasterPaintEngine);
1343 if (region.rectCount() == 1) {
1344 clip(region.boundingRect(), op);
1348 QRasterPaintEngineState *s = state();
1349 const QClipData *clip = d->clip();
1350 const QClipData *baseClip = d->baseClip.data();
1352 if (op == Qt::NoClip) {
1353 qrasterpaintengine_state_setNoClip(s);
1354 } else if (s->matrix.type() > QTransform::TxScale
1355 || op == Qt::UniteClip
1356 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1357 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1358 QPaintEngineEx::clip(region, op);
1360 const QClipData *curClip;
1363 if (op == Qt::IntersectClip)
1368 if (s->flags.has_clip_ownership) {
1372 newClip = new QClipData(d->rasterBuffer->height());
1374 s->flags.has_clip_ownership = true;
1377 QRegion r = s->matrix.map(region);
1378 if (curClip->hasRectClip)
1379 newClip->setClipRegion(r & curClip->clipRect);
1380 else if (curClip->hasRegionClip)
1381 newClip->setClipRegion(r & curClip->clipRegion);
1383 qrasterpaintengine_dirty_clip(d, s);
1390 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1392 #ifdef QT_DEBUG_DRAW
1393 qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1396 if (!fillData->blend)
1399 Q_D(QRasterPaintEngine);
1401 const QRectF controlPointRect = path.controlPointRect();
1403 QRasterPaintEngineState *s = state();
1404 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1405 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1406 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1407 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1408 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1409 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1411 if (!s->flags.antialiased && !do_clip) {
1412 d->initializeRasterizer(fillData);
1413 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1417 ensureOutlineMapper();
1418 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1421 static void fillRect_normalized(const QRect &r, QSpanData *data,
1422 QRasterPaintEnginePrivate *pe)
1426 bool rectClipped = true;
1429 x1 = qMax(r.x(), data->clip->xmin);
1430 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1431 y1 = qMax(r.y(), data->clip->ymin);
1432 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1433 rectClipped = data->clip->hasRectClip;
1436 x1 = qMax(r.x(), pe->deviceRect.x());
1437 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1438 y1 = qMax(r.y(), pe->deviceRect.y());
1439 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1441 x1 = qMax(r.x(), 0);
1442 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1443 y1 = qMax(r.y(), 0);
1444 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1447 if (x2 <= x1 || y2 <= y1)
1450 const int width = x2 - x1;
1451 const int height = y2 - y1;
1453 bool isUnclipped = rectClipped
1454 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1456 if (pe && isUnclipped) {
1457 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1459 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1460 || (mode == QPainter::CompositionMode_SourceOver
1461 && qAlpha(data->solid.color) == 255)))
1463 data->fillRect(data->rasterBuffer, x1, y1, width, height,
1469 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1471 const int nspans = 256;
1472 QT_FT_Span spans[nspans];
1474 Q_ASSERT(data->blend);
1477 int n = qMin(nspans, y2 - y);
1481 spans[i].len = width;
1483 spans[i].coverage = 255;
1487 blend(n, spans, data);
1495 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1497 #ifdef QT_DEBUG_DRAW
1498 qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1500 Q_D(QRasterPaintEngine);
1502 QRasterPaintEngineState *s = state();
1506 if (s->brushData.blend) {
1507 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1508 const QRect *r = rects;
1509 const QRect *lastRect = rects + rectCount;
1511 int offset_x = int(s->matrix.dx());
1512 int offset_y = int(s->matrix.dy());
1513 while (r < lastRect) {
1514 QRect rect = r->normalized();
1515 QRect rr = rect.translated(offset_x, offset_y);
1516 fillRect_normalized(rr, &s->brushData, d);
1520 QRectVectorPath path;
1521 for (int i=0; i<rectCount; ++i) {
1523 fill(path, s->brush);
1529 if (s->penData.blend) {
1530 QRectVectorPath path;
1531 if (s->flags.fast_pen) {
1532 QCosmeticStroker stroker(s, d->deviceRect);
1533 for (int i = 0; i < rectCount; ++i) {
1535 stroker.drawPath(path);
1538 for (int i = 0; i < rectCount; ++i) {
1540 stroke(path, s->pen);
1549 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1551 #ifdef QT_DEBUG_DRAW
1552 qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1554 #ifdef QT_FAST_SPANS
1555 Q_D(QRasterPaintEngine);
1557 QRasterPaintEngineState *s = state();
1560 if (s->flags.tx_noshear) {
1562 if (s->brushData.blend) {
1563 d->initializeRasterizer(&s->brushData);
1564 for (int i = 0; i < rectCount; ++i) {
1565 const QRectF &rect = rects[i].normalized();
1568 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1569 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1570 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1575 if (s->penData.blend) {
1576 QRectVectorPath path;
1577 if (s->flags.fast_pen) {
1578 QCosmeticStroker stroker(s, d->deviceRect);
1579 for (int i = 0; i < rectCount; ++i) {
1581 stroker.drawPath(path);
1584 for (int i = 0; i < rectCount; ++i) {
1586 QPaintEngineEx::stroke(path, s->lastPen);
1593 #endif // QT_FAST_SPANS
1594 QPaintEngineEx::drawRects(rects, rectCount);
1601 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1603 Q_D(QRasterPaintEngine);
1604 QRasterPaintEngineState *s = state();
1607 if (!s->penData.blend)
1610 if (s->flags.fast_pen) {
1611 QCosmeticStroker stroker(s, d->deviceRect);
1612 stroker.drawPath(path);
1613 } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1614 qreal width = s->lastPen.isCosmetic()
1615 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1616 : qpen_widthf(s->lastPen) * s->txscale;
1618 qreal dashOffset = s->lastPen.dashOffset();
1620 qreal patternLength = 0;
1621 const QVector<qreal> pattern = s->lastPen.dashPattern();
1622 for (int i = 0; i < pattern.size(); ++i)
1623 patternLength += pattern.at(i);
1625 if (patternLength > 0) {
1626 int n = qFloor(dashOffset / patternLength);
1627 dashOffset -= n * patternLength;
1628 while (dashOffset >= pattern.at(dashIndex)) {
1629 dashOffset -= pattern.at(dashIndex);
1630 if (++dashIndex >= pattern.size())
1636 Q_D(QRasterPaintEngine);
1637 d->initializeRasterizer(&s->penData);
1638 int lineCount = path.elementCount() / 2;
1639 const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1641 for (int i = 0; i < lineCount; ++i) {
1642 if (lines[i].p1() == lines[i].p2()) {
1643 if (s->lastPen.capStyle() != Qt::FlatCap) {
1644 QPointF p = lines[i].p1();
1645 QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1646 QPointF(p.x() + width*0.5, p.y())));
1647 d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1652 const QLineF line = s->matrix.map(lines[i]);
1653 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1654 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1655 width / line.length(),
1656 s->lastPen.capStyle() == Qt::SquareCap);
1658 d->rasterizeLine_dashed(line, width,
1659 &dashIndex, &dashOffset, &inDash);
1664 QPaintEngineEx::stroke(path, pen);
1667 static inline QRect toNormalizedFillRect(const QRectF &rect)
1669 int x1 = qRound(rect.x());
1670 int y1 = qRound(rect.y());
1671 int x2 = qRound(rect.right());
1672 int y2 = qRound(rect.bottom());
1679 return QRect(x1, y1, x2 - x1, y2 - y1);
1685 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1689 #ifdef QT_DEBUG_DRAW
1690 QRectF rf = path.controlPointRect();
1691 qDebug() << "QRasterPaintEngine::fill(): "
1692 << "size=" << path.elementCount()
1693 << ", hints=" << hex << path.hints()
1697 Q_D(QRasterPaintEngine);
1698 QRasterPaintEngineState *s = state();
1701 if (!s->brushData.blend)
1704 if (path.shape() == QVectorPath::RectangleHint) {
1705 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1706 const qreal *p = path.points();
1707 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1708 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1709 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1713 if (s->flags.tx_noshear) {
1714 d->initializeRasterizer(&s->brushData);
1715 // ### Is normalizing really necessary here?
1716 const qreal *p = path.points();
1717 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1719 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1720 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1721 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1727 // ### Optimize for non transformed ellipses and rectangles...
1728 QRectF cpRect = path.controlPointRect();
1729 const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1730 ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1733 // const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1734 // || deviceRect.right() > QT_RASTER_COORD_LIMIT
1735 // || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1736 // || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1738 // ### Falonc: implement....
1739 // if (!s->flags.antialiased && !do_clip) {
1740 // d->initializeRasterizer(&s->brushData);
1741 // d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1745 ensureOutlineMapper();
1746 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1749 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1751 Q_D(QRasterPaintEngine);
1752 QRasterPaintEngineState *s = state();
1754 if (!s->flags.antialiased) {
1755 uint txop = s->matrix.type();
1756 if (txop == QTransform::TxNone) {
1757 fillRect_normalized(toNormalizedFillRect(r), data, d);
1759 } else if (txop == QTransform::TxTranslate) {
1760 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1761 fillRect_normalized(rr, data, d);
1763 } else if (txop == QTransform::TxScale) {
1764 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1765 fillRect_normalized(rr, data, d);
1770 if (s->flags.tx_noshear) {
1771 d->initializeRasterizer(data);
1772 QRectF nr = r.normalized();
1773 if (!nr.isEmpty()) {
1774 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1775 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1776 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1783 ensureOutlineMapper();
1784 fillPath(path, data);
1790 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1792 #ifdef QT_DEBUG_DRAW
1793 qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1795 QRasterPaintEngineState *s = state();
1798 if (!s->brushData.blend)
1801 fillRect(r, &s->brushData);
1807 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1809 #ifdef QT_DEBUG_DRAW
1810 qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1812 Q_D(QRasterPaintEngine);
1813 QRasterPaintEngineState *s = state();
1815 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1816 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1817 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1820 d->solid_color_filler.clip = d->clip();
1821 d->solid_color_filler.adjustSpanMethods();
1822 fillRect(r, &d->solid_color_filler);
1825 static inline bool isAbove(const QPointF *a, const QPointF *b)
1827 return a->y() < b->y();
1830 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1835 Q_ASSERT(pointCount >= 2);
1837 QVector<const QPointF *> sorted;
1838 sorted.reserve(pointCount);
1840 upper->reserve(pointCount * 3 / 4);
1841 lower->reserve(pointCount * 3 / 4);
1843 for (int i = 0; i < pointCount; ++i)
1844 sorted << points + i;
1846 qSort(sorted.begin(), sorted.end(), isAbove);
1848 qreal splitY = sorted.at(sorted.size() / 2)->y();
1850 const QPointF *end = points + pointCount;
1851 const QPointF *last = end - 1;
1853 QVector<QPointF> *bin[2] = { upper, lower };
1855 for (const QPointF *p = points; p < end; ++p) {
1856 int side = p->y() < splitY;
1857 int lastSide = last->y() < splitY;
1859 if (side != lastSide) {
1860 if (qFuzzyCompare(p->y(), splitY)) {
1861 bin[!side]->append(*p);
1862 } else if (qFuzzyCompare(last->y(), splitY)) {
1863 bin[side]->append(*last);
1865 QPointF delta = *p - *last;
1866 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1868 bin[0]->append(intersection);
1869 bin[1]->append(intersection);
1873 bin[side]->append(*p);
1878 // give up if we couldn't reduce the point count
1879 return upper->size() < pointCount && lower->size() < pointCount;
1885 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1887 Q_D(QRasterPaintEngine);
1888 QRasterPaintEngineState *s = state();
1890 const int maxPoints = 0xffff;
1892 // max amount of points that raster engine can reliably handle
1893 if (pointCount > maxPoints) {
1894 QVector<QPointF> upper, lower;
1896 if (splitPolygon(points, pointCount, &upper, &lower)) {
1897 fillPolygon(upper.constData(), upper.size(), mode);
1898 fillPolygon(lower.constData(), lower.size(), mode);
1900 qWarning("Polygon too complex for filling.");
1905 // Compose polygon fill..,
1906 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1907 ensureOutlineMapper();
1908 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1911 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1913 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1919 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1921 Q_D(QRasterPaintEngine);
1922 QRasterPaintEngineState *s = state();
1924 #ifdef QT_DEBUG_DRAW
1925 qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1926 for (int i=0; i<pointCount; ++i)
1927 qDebug() << " - " << points[i];
1929 Q_ASSERT(pointCount >= 2);
1931 if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1932 QRectF r(points[0], points[2]);
1938 if (mode != PolylineMode) {
1941 if (s->brushData.blend) {
1942 fillPolygon(points, pointCount, mode);
1946 // Do the outline...
1947 if (s->penData.blend) {
1948 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1949 if (s->flags.fast_pen) {
1950 QCosmeticStroker stroker(s, d->deviceRect);
1951 stroker.drawPath(vp);
1953 QPaintEngineEx::stroke(vp, s->lastPen);
1961 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1963 Q_D(QRasterPaintEngine);
1964 QRasterPaintEngineState *s = state();
1966 #ifdef QT_DEBUG_DRAW
1967 qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1968 for (int i=0; i<pointCount; ++i)
1969 qDebug() << " - " << points[i];
1971 Q_ASSERT(pointCount >= 2);
1972 if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1973 QRect r(points[0].x(),
1975 points[2].x() - points[0].x(),
1976 points[2].y() - points[0].y());
1984 if (mode != PolylineMode) {
1986 if (s->brushData.blend) {
1987 // Compose polygon fill..,
1988 ensureOutlineMapper();
1989 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1990 d->outlineMapper->moveTo(*points);
1991 const QPoint *p = points;
1992 const QPoint *ep = points + pointCount - 1;
1994 d->outlineMapper->lineTo(*(++p));
1996 d->outlineMapper->endOutline();
1999 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2001 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2005 // Do the outline...
2006 if (s->penData.blend) {
2007 int count = pointCount * 2;
2008 QVarLengthArray<qreal> fpoints(count);
2009 for (int i=0; i<count; ++i)
2010 fpoints[i] = ((int *) points)[i];
2011 QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2013 if (s->flags.fast_pen) {
2014 QCosmeticStroker stroker(s, d->deviceRect);
2015 stroker.drawPath(vp);
2017 QPaintEngineEx::stroke(vp, s->lastPen);
2025 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2027 #ifdef QT_DEBUG_DRAW
2028 qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2031 QPixmapData *pd = pixmap.pixmapData();
2032 if (pd->classId() == QPixmapData::RasterClass) {
2033 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2034 if (image.depth() == 1) {
2035 Q_D(QRasterPaintEngine);
2036 QRasterPaintEngineState *s = state();
2037 if (s->matrix.type() <= QTransform::TxTranslate) {
2039 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2041 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2044 QRasterPaintEngine::drawImage(pos, image);
2047 const QImage image = pixmap.toImage();
2048 if (pixmap.depth() == 1) {
2049 Q_D(QRasterPaintEngine);
2050 QRasterPaintEngineState *s = state();
2051 if (s->matrix.type() <= QTransform::TxTranslate) {
2053 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2055 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2058 QRasterPaintEngine::drawImage(pos, image);
2066 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2068 #ifdef QT_DEBUG_DRAW
2069 qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2072 QPixmapData* pd = pixmap.pixmapData();
2073 if (pd->classId() == QPixmapData::RasterClass) {
2074 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2075 if (image.depth() == 1) {
2076 Q_D(QRasterPaintEngine);
2077 QRasterPaintEngineState *s = state();
2078 if (s->matrix.type() <= QTransform::TxTranslate
2079 && r.size() == sr.size()
2080 && r.size() == pixmap.size()) {
2082 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2085 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2088 drawImage(r, image, sr);
2091 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2092 const QImage image = pd->toImage(clippedSource);
2093 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2094 if (image.depth() == 1) {
2095 Q_D(QRasterPaintEngine);
2096 QRasterPaintEngineState *s = state();
2097 if (s->matrix.type() <= QTransform::TxTranslate
2098 && r.size() == sr.size()
2099 && r.size() == pixmap.size()) {
2101 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2104 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2107 drawImage(r, image, translatedSource);
2112 // assumes that rect has positive width and height
2113 static inline const QRect toRect_normalized(const QRectF &rect)
2115 const int x = qRound(rect.x());
2116 const int y = qRound(rect.y());
2117 const int w = int(rect.width() + qreal(0.5));
2118 const int h = int(rect.height() + qreal(0.5));
2120 return QRect(x, y, w, h);
2123 static inline int fast_ceil_positive(const qreal &v)
2125 const int iv = int(v);
2132 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2134 const int xmin = int(rect.x());
2135 const int xmax = int(fast_ceil_positive(rect.right()));
2136 const int ymin = int(rect.y());
2137 const int ymax = int(fast_ceil_positive(rect.bottom()));
2138 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2144 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2146 #ifdef QT_DEBUG_DRAW
2147 qDebug() << " - QRasterPaintEngine::drawImage(), p=" << p << " image=" << img.size() << "depth=" << img.depth();
2150 Q_D(QRasterPaintEngine);
2151 QRasterPaintEngineState *s = state();
2153 if (s->matrix.type() > QTransform::TxTranslate) {
2154 drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2156 QRectF(0, 0, img.width(), img.height()));
2159 const QClipData *clip = d->clip();
2160 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2162 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2163 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2166 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2168 } else if (clip->hasRectClip) {
2169 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2177 d->image_filler.clip = clip;
2178 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2179 if (!d->image_filler.blend)
2181 d->image_filler.dx = -pt.x();
2182 d->image_filler.dy = -pt.y();
2183 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2185 fillRect_normalized(rr, &d->image_filler, d);
2190 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2192 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2203 inline RotationType qRotationType(const QTransform &transform)
2205 QTransform::TransformationType type = transform.type();
2207 if (type > QTransform::TxRotate)
2210 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2211 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2214 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2215 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2218 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2219 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2225 inline bool isPixelAligned(const QRectF &rect) {
2226 return QRectF(rect.toRect()) == rect;
2233 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2234 Qt::ImageConversionFlags)
2236 #ifdef QT_DEBUG_DRAW
2237 qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2243 Q_D(QRasterPaintEngine);
2244 QRasterPaintEngineState *s = state();
2245 int sr_l = qFloor(sr.left());
2246 int sr_r = qCeil(sr.right()) - 1;
2247 int sr_t = qFloor(sr.top());
2248 int sr_b = qCeil(sr.bottom()) - 1;
2250 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2251 QTransform old = s->matrix;
2253 // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2254 QRgb color = img.pixel(sr_l, sr_t);
2255 switch (img.format()) {
2256 case QImage::Format_ARGB32_Premultiplied:
2257 case QImage::Format_ARGB8565_Premultiplied:
2258 case QImage::Format_ARGB6666_Premultiplied:
2259 case QImage::Format_ARGB8555_Premultiplied:
2260 case QImage::Format_ARGB4444_Premultiplied:
2261 // Combine premultiplied color with the opacity set on the painter.
2262 d->solid_color_filler.solid.color =
2263 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2264 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2267 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2271 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2272 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2276 d->solid_color_filler.clip = d->clip();
2277 d->solid_color_filler.adjustSpanMethods();
2278 fillRect(r, &d->solid_color_filler);
2284 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2286 const QClipData *clip = d->clip();
2288 if (s->matrix.type() > QTransform::TxTranslate
2290 && (!clip || clip->hasRectClip)
2291 && s->intOpacity == 256
2292 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2293 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2294 && d->rasterBuffer->format == img.format()
2295 && (d->rasterBuffer->format == QImage::Format_RGB16
2296 || d->rasterBuffer->format == QImage::Format_RGB32
2297 || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2298 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2300 RotationType rotationType = qRotationType(s->matrix);
2302 if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2303 QRectF transformedTargetRect = s->matrix.mapRect(r);
2305 if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2306 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2308 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2309 if (clippedTransformedTargetRect.isNull())
2312 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2314 QRect clippedSourceRect
2315 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2316 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2318 uint dbpl = d->rasterBuffer->bytesPerLine();
2319 uint sbpl = img.bytesPerLine();
2321 uchar *dst = d->rasterBuffer->buffer();
2322 uint bpp = img.depth() >> 3;
2324 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2325 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2327 uint cw = clippedSourceRect.width();
2328 uint ch = clippedSourceRect.height();
2330 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2337 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2339 QRectF targetBounds = s->matrix.mapRect(r);
2340 bool exceedsPrecision = targetBounds.width() > 0xffff
2341 || targetBounds.height() > 0xffff;
2343 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2344 if (s->matrix.type() > QTransform::TxScale) {
2345 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2346 if (func && (!clip || clip->hasRectClip)) {
2347 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2348 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2349 s->matrix, s->intOpacity);
2353 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2354 if (func && (!clip || clip->hasRectClip)) {
2355 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2356 img.bits(), img.bytesPerLine(),
2357 qt_mapRect_non_normalizing(r, s->matrix), sr,
2358 !clip ? d->deviceRect : clip->clipRect,
2365 QTransform copy = s->matrix;
2366 copy.translate(r.x(), r.y());
2368 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2369 copy.translate(-sr.x(), -sr.y());
2371 d->image_filler_xform.clip = clip;
2372 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2373 if (!d->image_filler_xform.blend)
2375 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2377 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2378 QRectF rr = s->matrix.mapRect(r);
2380 const int x1 = qRound(rr.x());
2381 const int y1 = qRound(rr.y());
2382 const int x2 = qRound(rr.right());
2383 const int y2 = qRound(rr.bottom());
2385 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2389 #ifdef QT_FAST_SPANS
2391 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2392 d->initializeRasterizer(&d->image_filler_xform);
2393 d->rasterizer->setAntialiased(s->flags.antialiased);
2395 const QRectF &rect = r.normalized();
2396 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2397 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2399 if (s->flags.tx_noshear)
2400 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2402 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2408 QTransform m = s->matrix;
2409 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2410 m.m21(), m.m22(), m.m23(),
2411 m.m31(), m.m32(), m.m33());
2412 fillPath(path, &d->image_filler_xform);
2415 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2416 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2418 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2420 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2422 } else if (clip->hasRectClip) {
2423 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2429 d->image_filler.clip = clip;
2430 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2431 if (!d->image_filler.blend)
2433 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2434 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2437 rr.translate(s->matrix.dx(), s->matrix.dy());
2439 const int x1 = qRound(rr.x());
2440 const int y1 = qRound(rr.y());
2441 const int x2 = qRound(rr.right());
2442 const int y2 = qRound(rr.bottom());
2444 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2451 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2453 #ifdef QT_DEBUG_DRAW
2454 qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2456 Q_D(QRasterPaintEngine);
2457 QRasterPaintEngineState *s = state();
2461 QPixmapData *pd = pixmap.pixmapData();
2462 if (pd->classId() == QPixmapData::RasterClass) {
2463 image = static_cast<QRasterPixmapData *>(pd)->image;
2465 image = pixmap.toImage();
2468 if (image.depth() == 1)
2469 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2471 if (s->matrix.type() > QTransform::TxTranslate) {
2472 QTransform copy = s->matrix;
2473 copy.translate(r.x(), r.y());
2474 copy.translate(-sr.x(), -sr.y());
2475 d->image_filler_xform.clip = d->clip();
2476 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2477 if (!d->image_filler_xform.blend)
2479 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2481 #ifdef QT_FAST_SPANS
2483 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2484 d->initializeRasterizer(&d->image_filler_xform);
2485 d->rasterizer->setAntialiased(s->flags.antialiased);
2487 const QRectF &rect = r.normalized();
2488 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2489 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2490 if (s->flags.tx_noshear)
2491 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2493 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2499 fillPath(path, &d->image_filler_xform);
2501 d->image_filler.clip = d->clip();
2503 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2504 if (!d->image_filler.blend)
2506 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2507 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2510 rr.translate(s->matrix.dx(), s->matrix.dy());
2511 fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2517 static inline bool monoVal(const uchar* s, int x)
2519 return (s[x>>3] << (x&7)) & 0x80;
2525 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2527 Q_D(QRasterPaintEngine);
2528 QRasterPaintEngineState *s = state();
2530 if (!s->penData.blend)
2533 QRasterBuffer *rb = d->rasterBuffer.data();
2535 const QRect rect(rx, ry, w, h);
2536 const QClipData *clip = d->clip();
2537 bool unclipped = false;
2539 // inlined QRect::intersects
2540 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2541 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2543 if (clip->hasRectClip) {
2544 unclipped = rx > clip->xmin
2545 && rx + w < clip->xmax
2547 && ry + h < clip->ymax;
2553 // inlined QRect::intersects
2554 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2555 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2559 // inlined QRect::contains
2560 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2561 && rect.top() >= 0 && rect.bottom() < rb->height();
2563 unclipped = contains && d->isUnclipped_normalized(rect);
2566 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2567 const uchar * scanline = static_cast<const uchar *>(src);
2569 if (s->flags.fast_text) {
2572 if (s->penData.bitmapBlit) {
2573 s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2574 scanline, w, h, bpl);
2577 } else if (depth == 8) {
2578 if (s->penData.alphamapBlit) {
2579 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2580 scanline, w, h, bpl, 0);
2583 } else if (depth == 32) {
2584 // (A)RGB Alpha mask where the alpha component is not used.
2585 if (s->penData.alphaRGBBlit) {
2586 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2587 (const uint *) scanline, w, h, bpl / 4, 0);
2591 } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2592 // (A)RGB Alpha mask where the alpha component is not used.
2594 int nx = qMax(0, rx);
2595 int ny = qMax(0, ry);
2597 // Move scanline pointer to compensate for moved x and y
2598 int xdiff = nx - rx;
2599 int ydiff = ny - ry;
2600 scanline += ydiff * bpl;
2601 scanline += xdiff * (depth == 32 ? 4 : 1);
2606 if (nx + w > d->rasterBuffer->width())
2607 w = d->rasterBuffer->width() - nx;
2608 if (ny + h > d->rasterBuffer->height())
2609 h = d->rasterBuffer->height() - ny;
2614 if (depth == 8 && s->penData.alphamapBlit) {
2615 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2616 scanline, w, h, bpl, clip);
2617 } else if (depth == 32 && s->penData.alphaRGBBlit) {
2618 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2619 (const uint *) scanline, w, h, bpl / 4, clip);
2634 scanline += bpl * y0;
2638 w = qMin(w, rb->width() - qMax(0, rx));
2639 h = qMin(h, rb->height() - qMax(0, ry));
2641 if (w <= 0 || h <= 0)
2644 const int NSPANS = 256;
2645 QSpan spans[NSPANS];
2648 const int x1 = x0 + w;
2649 const int y1 = y0 + h;
2652 for (int y = y0; y < y1; ++y) {
2653 for (int x = x0; x < x1; ) {
2654 if (!monoVal(scanline, x)) {
2659 if (current == NSPANS) {
2660 blend(current, spans, &s->penData);
2663 spans[current].x = x + rx;
2664 spans[current].y = y + ry;
2665 spans[current].coverage = 255;
2668 // extend span until we find a different one.
2669 while (x < x1 && monoVal(scanline, x)) {
2673 spans[current].len = len;
2678 } else if (depth == 8) {
2679 for (int y = y0; y < y1; ++y) {
2680 for (int x = x0; x < x1; ) {
2681 // Skip those with 0 coverage
2682 if (scanline[x] == 0) {
2687 if (current == NSPANS) {
2688 blend(current, spans, &s->penData);
2691 int coverage = scanline[x];
2692 spans[current].x = x + rx;
2693 spans[current].y = y + ry;
2694 spans[current].coverage = coverage;
2698 // extend span until we find a different one.
2699 while (x < x1 && scanline[x] == coverage) {
2703 spans[current].len = len;
2708 } else { // 32-bit alpha...
2709 uint *sl = (uint *) src;
2710 for (int y = y0; y < y1; ++y) {
2711 for (int x = x0; x < x1; ) {
2712 // Skip those with 0 coverage
2713 if ((sl[x] & 0x00ffffff) == 0) {
2718 if (current == NSPANS) {
2719 blend(current, spans, &s->penData);
2722 uint rgbCoverage = sl[x];
2723 int coverage = qGreen(rgbCoverage);
2724 spans[current].x = x + rx;
2725 spans[current].y = y + ry;
2726 spans[current].coverage = coverage;
2730 // extend span until we find a different one.
2731 while (x < x1 && sl[x] == rgbCoverage) {
2735 spans[current].len = len;
2738 sl += bpl / sizeof(uint);
2741 // qDebug() << "alphaPenBlt: num spans=" << current
2742 // << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2743 // Call span func for current set of spans.
2745 blend(current, spans, &s->penData);
2748 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2749 const QFixedPoint *positions, QFontEngine *fontEngine)
2751 Q_D(QRasterPaintEngine);
2752 QRasterPaintEngineState *s = state();
2754 #if !defined(QT_NO_FREETYPE)
2755 if (fontEngine->type() == QFontEngine::Freetype) {
2756 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2757 QFontEngineFT::GlyphFormat neededFormat =
2758 painter()->device()->devType() == QInternal::Widget
2759 ? fe->defaultGlyphFormat()
2760 : QFontEngineFT::Format_A8;
2762 if (d_func()->mono_surface
2763 || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2765 neededFormat = QFontEngineFT::Format_Mono;
2767 if (neededFormat == QFontEngineFT::Format_None)
2768 neededFormat = QFontEngineFT::Format_A8;
2770 QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2771 if (s->matrix.type() >= QTransform::TxScale) {
2772 if (s->matrix.isAffine())
2773 gset = fe->loadTransformedGlyphSet(s->matrix);
2778 if (!gset || gset->outline_drawing
2779 || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2782 FT_Face lockedFace = 0;
2785 switch (neededFormat) {
2786 case QFontEngineFT::Format_Mono:
2789 case QFontEngineFT::Format_A8:
2792 case QFontEngineFT::Format_A32:
2800 for (int i = 0; i < numGlyphs; i++) {
2801 QFixed spp = fe->subPixelPositionForX(positions[i].x);
2802 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2804 if (!glyph || glyph->format != neededFormat) {
2806 lockedFace = fe->lockFace();
2807 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2810 if (!glyph || !glyph->data)
2814 switch (neededFormat) {
2815 case QFontEngineFT::Format_Mono:
2816 pitch = ((glyph->width + 31) & ~31) >> 3;
2818 case QFontEngineFT::Format_A8:
2819 pitch = (glyph->width + 3) & ~3;
2821 case QFontEngineFT::Format_A32:
2822 pitch = glyph->width * 4;
2829 alphaPenBlt(glyph->data, pitch, depth,
2830 qFloor(positions[i].x) + glyph->x,
2831 qFloor(positions[i].y) - glyph->y,
2832 glyph->width, glyph->height);
2839 QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2841 QImageTextureGlyphCache *cache =
2842 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2844 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2845 fontEngine->setGlyphCache(0, cache);
2848 cache->populate(fontEngine, numGlyphs, glyphs, positions);
2849 cache->fillInPendingGlyphs();
2851 const QImage &image = cache->image();
2852 int bpl = image.bytesPerLine();
2854 int depth = image.depth();
2858 leftShift = 2; // multiply by 4
2859 else if (depth == 1)
2860 rightShift = 3; // divide by 8
2862 int margin = cache->glyphMargin();
2863 const uchar *bits = image.bits();
2864 for (int i=0; i<numGlyphs; ++i) {
2866 QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2867 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2868 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2872 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2873 int y = qFloor(positions[i].y) - c.baseLineY - margin;
2875 // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2878 // c.baseLineX, c.baseLineY,
2881 // positions[i].x.toInt(), positions[i].y.toInt());
2883 alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2889 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2890 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2892 Q_D(QRasterPaintEngine);
2893 QRasterPaintEngineState *s = state();
2895 QFontEngine *fontEngine = ti.fontEngine;
2896 if (fontEngine->type() != QFontEngine::S60FontEngine) {
2897 QPaintEngineEx::drawTextItem(p, ti);
2901 QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2903 QVarLengthArray<QFixedPoint> positions;
2904 QVarLengthArray<glyph_t> glyphs;
2905 QTransform matrix = s->matrix;
2906 matrix.translate(p.x(), p.y());
2907 if (matrix.type() == QTransform::TxScale)
2908 fe->setFontScale(matrix.m11());
2909 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2911 for (int i=0; i<glyphs.size(); ++i) {
2912 TOpenFontCharMetrics tmetrics;
2913 const TUint8 *glyphBitmapBytes;
2914 TSize glyphBitmapSize;
2915 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2916 const int x = qFloor(positions[i].x + tmetrics.HorizBearingX());
2917 const int y = qFloor(positions[i].y - tmetrics.HorizBearingY());
2918 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2921 if (matrix.type() == QTransform::TxScale)
2922 fe->setFontScale(1.0);
2926 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2929 * Returns true if the rectangle is completely within the current clip
2930 * state of the paint engine.
2932 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2934 const QClipData *cl = clip();
2936 // inline contains() for performance (we know the rects are normalized)
2937 const QRect &r1 = deviceRect;
2938 return (r.left() >= r1.left() && r.right() <= r1.right()
2939 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2943 if (cl->hasRectClip) {
2944 // currently all painting functions clips to deviceRect internally
2945 if (cl->clipRect == deviceRect)
2948 // inline contains() for performance (we know the rects are normalized)
2949 const QRect &r1 = cl->clipRect;
2950 return (r.left() >= r1.left() && r.right() <= r1.right()
2951 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2953 return qt_region_strictContains(cl->clipRegion, r);
2957 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2960 Q_Q(const QRasterPaintEngine);
2961 const QRasterPaintEngineState *s = q->state();
2962 const QClipData *cl = clip();
2964 QRect r = rect.normalized();
2965 // inline contains() for performance (we know the rects are normalized)
2966 const QRect &r1 = deviceRect;
2967 return (r.left() >= r1.left() && r.right() <= r1.right()
2968 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2972 // currently all painting functions that call this function clip to deviceRect internally
2973 if (cl->hasRectClip && cl->clipRect == deviceRect)
2976 if (s->flags.antialiased)
2979 QRect r = rect.normalized();
2981 r.setX(r.x() - penWidth);
2982 r.setY(r.y() - penWidth);
2983 r.setWidth(r.width() + 2 * penWidth);
2984 r.setHeight(r.height() + 2 * penWidth);
2987 if (cl->hasRectClip) {
2988 // inline contains() for performance (we know the rects are normalized)
2989 const QRect &r1 = cl->clipRect;
2990 return (r.left() >= r1.left() && r.right() <= r1.right()
2991 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2993 return qt_region_strictContains(cl->clipRegion, r);
2997 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3000 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3004 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3005 const QSpanData *data) const
3007 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3011 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3012 const QSpanData *data) const
3014 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3020 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3025 QFontEngine *fontEngine = textItem->fontEngine();
3026 if (!supportsTransformations(fontEngine)) {
3027 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3030 QPaintEngineEx::drawStaticTextItem(textItem);
3037 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3039 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3040 QRasterPaintEngineState *s = state();
3042 #ifdef QT_DEBUG_DRAW
3043 Q_D(QRasterPaintEngine);
3044 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3045 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3052 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3054 if (!supportsTransformations(ti.fontEngine)) {
3055 QVarLengthArray<QFixedPoint> positions;
3056 QVarLengthArray<glyph_t> glyphs;
3058 QTransform matrix = s->matrix;
3059 matrix.translate(p.x(), p.y());
3061 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3063 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3067 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3068 if (s->matrix.type() <= QTransform::TxTranslate
3069 || (s->matrix.type() == QTransform::TxScale
3070 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3071 drawGlyphsS60(p, ti);
3074 #else // Q_WS_WIN || Q_WS_MAC
3076 QFontEngine *fontEngine = ti.fontEngine;
3078 #if defined(Q_WS_QWS)
3079 if (fontEngine->type() == QFontEngine::Box) {
3080 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3084 if (s->matrix.type() < QTransform::TxScale
3085 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3086 || (fontEngine->type() == QFontEngine::Proxy
3087 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3089 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3095 if (s->matrix.type() < QTransform::TxScale) {
3097 QVarLengthArray<QFixedPoint> positions;
3098 QVarLengthArray<glyph_t> glyphs;
3099 QTransform matrix = state()->transform();
3101 qreal _x = qFloor(p.x());
3102 qreal _y = qFloor(p.y());
3103 matrix.translate(_x, _y);
3105 fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3106 if (glyphs.size() == 0)
3109 for(int i = 0; i < glyphs.size(); i++) {
3110 QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3111 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3112 alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3113 qRound(positions[i].x + metrics.x),
3114 qRound(positions[i].y + metrics.y),
3115 img.width(), img.height());
3121 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3123 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3124 if (fontEngine->type() == QFontEngine::QPF2) {
3125 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3126 if (renderingEngine)
3127 fontEngine = renderingEngine;
3131 if (fontEngine->type() != QFontEngine::Freetype) {
3132 QPaintEngineEx::drawTextItem(p, ti);
3136 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3138 QTransform matrix = s->matrix;
3139 matrix.translate(p.x(), p.y());
3141 QVarLengthArray<QFixedPoint> positions;
3142 QVarLengthArray<glyph_t> glyphs;
3143 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3144 if (glyphs.size() == 0)
3147 if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3148 QPaintEngine::drawTextItem(p, ti);
3154 QPaintEngineEx::drawTextItem(p, ti);
3160 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3162 Q_D(QRasterPaintEngine);
3163 QRasterPaintEngineState *s = state();
3166 if (!s->penData.blend)
3169 if (!s->flags.fast_pen) {
3170 QPaintEngineEx::drawPoints(points, pointCount);
3174 QCosmeticStroker stroker(s, d->deviceRect);
3175 stroker.drawPoints(points, pointCount);
3179 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3181 Q_D(QRasterPaintEngine);
3182 QRasterPaintEngineState *s = state();
3185 if (!s->penData.blend)
3188 if (!s->flags.fast_pen) {
3189 QPaintEngineEx::drawPoints(points, pointCount);
3193 QCosmeticStroker stroker(s, d->deviceRect);
3194 stroker.drawPoints(points, pointCount);
3200 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3202 #ifdef QT_DEBUG_DRAW
3203 qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3205 Q_D(QRasterPaintEngine);
3206 QRasterPaintEngineState *s = state();
3209 if (!s->penData.blend)
3212 if (s->flags.fast_pen) {
3213 QCosmeticStroker stroker(s, d->deviceRect);
3214 for (int i=0; i<lineCount; ++i) {
3215 const QLine &l = lines[i];
3216 stroker.drawLine(l.p1(), l.p2());
3219 QPaintEngineEx::drawLines(lines, lineCount);
3223 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3229 Q_Q(QRasterPaintEngine);
3230 QRasterPaintEngineState *s = q->state();
3232 const QPen &pen = s->lastPen;
3233 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3234 const QVector<qreal> pattern = pen.dashPattern();
3236 qreal patternLength = 0;
3237 for (int i = 0; i < pattern.size(); ++i)
3238 patternLength += pattern.at(i);
3240 if (patternLength <= 0)
3243 qreal length = line.length();
3244 Q_ASSERT(length > 0);
3245 while (length > 0) {
3246 const bool rasterize = *inDash;
3247 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3250 if (dash >= length) {
3252 *dashOffset += dash / width;
3256 *inDash = !(*inDash);
3257 if (++*dashIndex >= pattern.size())
3264 if (rasterize && dash > 0)
3265 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3272 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3274 #ifdef QT_DEBUG_DRAW
3275 qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3277 Q_D(QRasterPaintEngine);
3278 QRasterPaintEngineState *s = state();
3281 if (!s->penData.blend)
3283 if (s->flags.fast_pen) {
3284 QCosmeticStroker stroker(s, d->deviceRect);
3285 for (int i=0; i<lineCount; ++i) {
3286 QLineF line = lines[i];
3287 stroker.drawLine(line.p1(), line.p2());
3290 QPaintEngineEx::drawLines(lines, lineCount);
3298 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3300 QPaintEngineEx::drawEllipse(rect);
3307 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3309 Q_D(QRasterPaintEngine);
3316 CGContextRef QRasterPaintEngine::getCGContext() const
3318 Q_D(const QRasterPaintEngine);
3319 return d->cgContext;
3327 void QRasterPaintEngine::setDC(HDC hdc) {
3328 Q_D(QRasterPaintEngine);
3335 HDC QRasterPaintEngine::getDC() const
3337 Q_D(const QRasterPaintEngine);
3344 void QRasterPaintEngine::releaseDC(HDC) const
3350 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3352 const QTransform &m = state()->matrix;
3353 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3354 QFontEngine::Type fontEngineType = fontEngine->type();
3355 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3356 || (m.type() <= QTransform::TxTranslate
3357 && (fontEngineType == QFontEngine::TestFontEngine
3358 || fontEngineType == QFontEngine::Box))) {
3362 return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3365 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3367 #if defined(Q_WS_MAC)
3368 // Mac font engines don't support scaling and rotation
3369 if (m.type() > QTransform::TxTranslate)
3371 if (m.type() >= QTransform::TxProject)
3375 if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3384 QPoint QRasterPaintEngine::coordinateOffset() const
3386 return QPoint(0, 0);
3390 Draws the given color \a spans with the specified \a color. The \a
3391 count parameter specifies the number of spans.
3393 The default implementation does nothing; reimplement this function
3394 to draw the given color \a spans with the specified \a color. Note
3395 that this function \e must be reimplemented if the framebuffer is
3398 \sa drawBufferSpan()
3400 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3401 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3406 qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3407 "a non memory-mapped device");
3411 \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3413 Draws the given \a buffer.
3415 The default implementation does nothing; reimplement this function
3416 to draw a buffer that contains more than one color. Note that this
3417 function \e must be reimplemented if the framebuffer is not
3420 The \a size parameter specifies the total size of the given \a
3421 buffer, while the \a length parameter specifies the number of
3422 pixels to draw. The buffer's position is given by (\a x, \a
3423 y). The provided \a alpha value is added to each pixel in the
3424 buffer when drawing.
3426 \sa drawColorSpans()
3428 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3429 int x, int y, int length, uint const_alpha)
3436 Q_UNUSED(const_alpha);
3437 qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3438 "a non memory-mapped device");
3442 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3447 Q_D(QRasterPaintEngine);
3449 Q_ASSERT(image.depth() == 1);
3451 const int spanCount = 256;
3452 QT_FT_Span spans[spanCount];
3456 int w = image.width();
3457 int h = image.height();
3458 int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3459 int ymin = qMax(qRound(pos.y()), 0);
3460 int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3461 int xmin = qMax(qRound(pos.x()), 0);
3463 int x_offset = xmin - qRound(pos.x());
3465 QImage::Format format = image.format();
3466 for (int y = ymin; y < ymax; ++y) {
3467 const uchar *src = image.scanLine(y - qRound(pos.y()));
3468 if (format == QImage::Format_MonoLSB) {
3469 for (int x = 0; x < xmax - xmin; ++x) {
3470 int src_x = x + x_offset;
3471 uchar pixel = src[src_x >> 3];
3476 if (pixel & (0x1 << (src_x & 7))) {
3477 spans[n].x = xmin + x;
3479 spans[n].coverage = 255;
3481 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3485 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3488 if (n == spanCount) {
3489 fg->blend(n, spans, fg);
3495 for (int x = 0; x < xmax - xmin; ++x) {
3496 int src_x = x + x_offset;
3497 uchar pixel = src[src_x >> 3];
3502 if (pixel & (0x80 >> (x & 7))) {
3503 spans[n].x = xmin + x;
3505 spans[n].coverage = 255;
3507 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3511 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3514 if (n == spanCount) {
3515 fg->blend(n, spans, fg);
3523 fg->blend(n, spans, fg);
3529 \enum QRasterPaintEngine::ClipType
3532 \value RectClip Indicates that the currently set clip is a single rectangle.
3533 \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3538 Returns the type of the clip currently set.
3540 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3542 Q_D(const QRasterPaintEngine);
3544 const QClipData *clip = d->clip();
3545 if (!clip || clip->hasRectClip)
3553 Returns the bounding rect of the currently set clip.
3555 QRect QRasterPaintEngine::clipBoundingRect() const
3557 Q_D(const QRasterPaintEngine);
3559 const QClipData *clip = d->clip();
3562 return d->deviceRect;
3564 if (clip->hasRectClip)
3565 return clip->clipRect;
3567 return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3570 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3572 Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3574 QVarLengthArray<short, 4096> buffer;
3576 QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3577 QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3578 result->initialize();
3580 for (int y = 0; y < c1->clipSpanHeight; ++y) {
3581 const QSpan *c1_spans = c1ClipLines[y].spans;
3582 int c1_count = c1ClipLines[y].count;
3583 const QSpan *c2_spans = c2ClipLines[y].spans;
3584 int c2_count = c2ClipLines[y].count;
3586 if (c1_count == 0 && c2_count == 0)
3588 if (c1_count == 0) {
3589 result->appendSpans(c2_spans, c2_count);
3591 } else if (c2_count == 0) {
3592 result->appendSpans(c1_spans, c1_count);
3596 // we need to merge the two
3598 // find required length
3599 int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3600 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3602 memset(buffer.data(), 0, buffer.size() * sizeof(short));
3604 // Fill with old spans.
3605 for (int i = 0; i < c1_count; ++i) {
3606 const QSpan *cs = c1_spans + i;
3607 for (int j=cs->x; j<cs->x + cs->len; ++j)
3608 buffer[j] = cs->coverage;
3611 // Fill with new spans
3612 for (int i = 0; i < c2_count; ++i) {
3613 const QSpan *cs = c2_spans + i;
3614 for (int j = cs->x; j < cs->x + cs->len; ++j) {
3615 buffer[j] += cs->coverage;
3616 if (buffer[j] > 255)
3624 // Skip to next span
3625 while (x < max && buffer[x] == 0) ++x;
3626 if (x >= max) break;
3629 int coverage = buffer[x];
3631 // Find length of span
3632 while (x < max && buffer[x] == coverage)
3635 result->appendSpan(sx, x - sx, y, coverage);
3640 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3642 Q_Q(QRasterPaintEngine);
3643 QRasterPaintEngineState *s = q->state();
3645 rasterizer->setAntialiased(s->flags.antialiased);
3647 QRect clipRect(deviceRect);
3649 // ### get from optimized rectbased QClipData
3651 const QClipData *c = clip();
3653 const QRect r(QPoint(c->xmin, c->ymin),
3654 QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3655 clipRect = clipRect.intersected(r);
3656 blend = data->blend;
3658 blend = data->unclipped_blend;
3661 rasterizer->setClipRect(clipRect);
3662 rasterizer->initialize(blend, data);
3665 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3666 ProcessSpans callback,
3667 QSpanData *spanData, QRasterBuffer *rasterBuffer)
3669 if (!callback || !outline)
3672 Q_Q(QRasterPaintEngine);
3673 QRasterPaintEngineState *s = q->state();
3675 if (!s->flags.antialiased) {
3676 initializeRasterizer(spanData);
3678 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3682 rasterizer->rasterize(outline, fillRule);
3686 rasterize(outline, callback, (void *)spanData, rasterBuffer);
3690 int q_gray_rendered_spans(QT_FT_Raster raster);
3693 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3694 ProcessSpans callback,
3695 void *userData, QRasterBuffer *)
3697 if (!callback || !outline)
3700 Q_Q(QRasterPaintEngine);
3701 QRasterPaintEngineState *s = q->state();
3703 if (!s->flags.antialiased) {
3704 rasterizer->setAntialiased(s->flags.antialiased);
3705 rasterizer->setClipRect(deviceRect);
3706 rasterizer->initialize(callback, userData);
3708 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3712 rasterizer->rasterize(outline, fillRule);
3716 // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3717 // minimize memory reallocations. However if initial size for
3718 // raster pool is changed for lower value, reallocations will
3720 const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3721 int rasterPoolSize = rasterPoolInitialSize;
3722 unsigned char *rasterPoolBase;
3723 #if defined(Q_WS_WIN64)
3725 // We make use of setjmp and longjmp in qgrayraster.c which requires
3726 // 16-byte alignment, hence we hardcode this requirement here..
3727 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3729 unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3730 rasterPoolBase = rasterPoolOnStack;
3732 Q_CHECK_PTR(rasterPoolBase);
3734 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3736 void *data = userData;
3738 QT_FT_BBox clip_box = { deviceRect.x(),
3740 deviceRect.x() + deviceRect.width(),
3741 deviceRect.y() + deviceRect.height() };
3743 QT_FT_Raster_Params rasterParams;
3744 rasterParams.target = 0;
3745 rasterParams.source = outline;
3746 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3747 rasterParams.gray_spans = 0;
3748 rasterParams.black_spans = 0;
3749 rasterParams.bit_test = 0;
3750 rasterParams.bit_set = 0;
3751 rasterParams.user = data;
3752 rasterParams.clip_box = clip_box;
3757 int rendered_spans = 0;
3761 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3762 rasterParams.gray_spans = callback;
3763 rasterParams.skip_spans = rendered_spans;
3764 error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3766 // Out of memory, reallocate some more and try again...
3767 if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3768 int new_size = rasterPoolSize * 2;
3769 if (new_size > 1024 * 1024) {
3770 qWarning("QPainter: Rasterization of primitive failed");
3774 rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3776 #if defined(Q_WS_WIN64)
3777 _aligned_free(rasterPoolBase);
3779 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3780 free(rasterPoolBase);
3783 rasterPoolSize = new_size;
3785 #if defined(Q_WS_WIN64)
3786 // We make use of setjmp and longjmp in qgrayraster.c which requires
3787 // 16-byte alignment, hence we hardcode this requirement here..
3788 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3790 (unsigned char *) malloc(rasterPoolSize);
3792 Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3794 qt_ft_grays_raster.raster_done(*grayRaster.data());
3795 qt_ft_grays_raster.raster_new(grayRaster.data());
3796 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3802 #if defined(Q_WS_WIN64)
3803 _aligned_free(rasterPoolBase);
3805 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3806 free(rasterPoolBase);
3810 void QRasterPaintEnginePrivate::recalculateFastImages()
3812 Q_Q(QRasterPaintEngine);
3813 QRasterPaintEngineState *s = q->state();
3815 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3816 && s->matrix.type() <= QTransform::TxShear;
3819 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3821 Q_Q(const QRasterPaintEngine);
3822 const QRasterPaintEngineState *s = q->state();
3824 return s->flags.fast_images
3825 && (mode == QPainter::CompositionMode_SourceOver
3826 || (mode == QPainter::CompositionMode_Source
3827 && !image.hasAlphaChannel()));
3830 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3832 Q_ASSERT(image.depth() == 1);
3834 QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3835 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3837 QRgb fg = PREMUL(color.rgba());
3840 int height = sourceImage.height();
3841 int width = sourceImage.width();
3842 for (int y=0; y<height; ++y) {
3843 uchar *source = sourceImage.scanLine(y);
3844 QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3845 if (!source || !target)
3846 QT_THROW(std::bad_alloc()); // we must have run out of memory
3847 for (int x=0; x < width; ++x)
3848 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3853 QRasterBuffer::~QRasterBuffer()
3857 void QRasterBuffer::init()
3859 compositionMode = QPainter::CompositionMode_SourceOver;
3860 monoDestinationWithClut = false;
3865 QImage::Format QRasterBuffer::prepare(QImage *image)
3867 m_buffer = (uchar *)image->bits();
3868 m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3869 m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3870 bytes_per_pixel = image->depth()/8;
3871 bytes_per_line = image->bytesPerLine();
3873 format = image->format();
3874 drawHelper = qDrawHelper + format;
3875 if (image->depth() == 1 && image->colorTable().size() == 2) {
3876 monoDestinationWithClut = true;
3877 destColor0 = PREMUL(image->colorTable()[0]);
3878 destColor1 = PREMUL(image->colorTable()[1]);
3884 void QRasterBuffer::resetBuffer(int val)
3886 memset(m_buffer, val, m_height*bytes_per_line);
3890 #if defined(Q_WS_QWS)
3891 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3893 m_buffer = reinterpret_cast<uchar*>(device->memory());
3894 m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3895 m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3896 bytes_per_pixel = device->depth() / 8;
3897 bytes_per_line = device->bytesPerLine();
3898 format = device->format();
3899 #ifndef QT_NO_RASTERCALLBACKS
3901 drawHelper = qDrawHelperCallback + format;
3904 drawHelper = qDrawHelper + format;
3907 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3911 return widget->frameGeometry().width();
3913 return widget->frameGeometry().height();
3918 return qt_paint_device_metric(widget, m);
3921 int QCustomRasterPaintDevice::bytesPerLine() const
3923 return (width() * depth() + 7) / 8;
3926 #elif defined(Q_OS_SYMBIAN)
3928 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3932 #endif // Q_OS_SYMBIAN
3935 \class QCustomRasterPaintDevice
3940 \brief The QCustomRasterPaintDevice class is provided to activate
3941 hardware accelerated paint engines in Qt for Embedded Linux.
3943 Note that this class is only available in \l{Qt for Embedded Linux}.
3945 In \l{Qt for Embedded Linux}, painting is a pure software
3946 implementation. But starting with Qt 4.2, it is
3947 possible to add an accelerated graphics driver to take advantage
3948 of available hardware resources.
3950 Hardware acceleration is accomplished by creating a custom screen
3951 driver, accelerating the copying from memory to the screen, and
3952 implementing a custom paint engine accelerating the various
3953 painting operations. Then a custom paint device (derived from the
3954 QCustomRasterPaintDevice class) and a custom window surface
3955 (derived from QWSWindowSurface) must be implemented to make
3956 \l{Qt for Embedded Linux} aware of the accelerated driver.
3958 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3959 documentation for details.
3961 \sa QRasterPaintEngine, QPaintDevice
3965 \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3967 Constructs a custom raster based paint device for the given
3968 top-level \a widget.
3972 \fn int QCustomRasterPaintDevice::bytesPerLine() const
3974 Returns the number of bytes per line in the framebuffer. Note that
3975 this number might be larger than the framebuffer width.
3979 \fn int QCustomRasterPaintDevice::devType() const
3984 \fn QImage::Format QCustomRasterPaintDevice::format() const
3986 Returns the format of the device's memory buffet.
3988 The default format is QImage::Format_ARGB32_Premultiplied. The
3989 only other valid format is QImage::Format_RGB16.
3993 \fn void * QCustomRasterPaintDevice::memory () const
3995 Returns a pointer to the paint device's memory buffer, or 0 if no
4000 \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4005 \fn QSize QCustomRasterPaintDevice::size () const
4010 QClipData::QClipData(int height)
4012 clipSpanHeight = height;
4017 xmin = xmax = ymin = ymax = 0;
4021 hasRectClip = hasRegionClip = false;
4024 QClipData::~QClipData()
4032 void QClipData::initialize()
4038 m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4040 Q_CHECK_PTR(m_clipLines);
4042 m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4043 allocated = clipSpanHeight;
4044 Q_CHECK_PTR(m_spans);
4050 m_clipLines[y].spans = 0;
4051 m_clipLines[y].count = 0;
4055 const int len = clipRect.width();
4058 QSpan *span = m_spans + count;
4062 span->coverage = 255;
4065 m_clipLines[y].spans = span;
4066 m_clipLines[y].count = 1;
4070 while (y < clipSpanHeight) {
4071 m_clipLines[y].spans = 0;
4072 m_clipLines[y].count = 0;
4075 } else if (hasRegionClip) {
4077 const QVector<QRect> rects = clipRegion.rects();
4078 const int numRects = rects.size();
4081 const int maxSpans = (ymax - ymin) * numRects;
4082 if (maxSpans > allocated) {
4083 m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4084 allocated = maxSpans;
4089 int firstInBand = 0;
4091 while (firstInBand < numRects) {
4092 const int currMinY = rects.at(firstInBand).y();
4093 const int currMaxY = currMinY + rects.at(firstInBand).height();
4095 while (y < currMinY) {
4096 m_clipLines[y].spans = 0;
4097 m_clipLines[y].count = 0;
4101 int lastInBand = firstInBand;
4102 while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4105 while (y < currMaxY) {
4107 m_clipLines[y].spans = m_spans + count;
4108 m_clipLines[y].count = lastInBand - firstInBand + 1;
4110 for (int r = firstInBand; r <= lastInBand; ++r) {
4111 const QRect &currRect = rects.at(r);
4112 QSpan *span = m_spans + count;
4113 span->x = currRect.x();
4114 span->len = currRect.width();
4116 span->coverage = 255;
4122 firstInBand = lastInBand + 1;
4125 Q_ASSERT(count <= allocated);
4127 while (y < clipSpanHeight) {
4128 m_clipLines[y].spans = 0;
4129 m_clipLines[y].count = 0;
4135 free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4140 free(m_clipLines); // same for clipLines
4146 void QClipData::fixup()
4151 ymin = ymax = xmin = xmax = 0;
4156 ymin = m_spans[0].y;
4157 ymax = m_spans[count-1].y + 1;
4161 const int firstLeft = m_spans[0].x;
4162 const int firstRight = m_spans[0].x + m_spans[0].len;
4165 for (int i = 0; i < count; ++i) {
4166 QT_FT_Span_& span = m_spans[i];
4169 if (span.y != y + 1 && y != -1)
4172 m_clipLines[y].spans = &span;
4173 m_clipLines[y].count = 1;
4175 ++m_clipLines[y].count;
4177 const int spanLeft = span.x;
4178 const int spanRight = spanLeft + span.len;
4180 if (spanLeft < xmin)
4183 if (spanRight > xmax)
4186 if (spanLeft != firstLeft || spanRight != firstRight)
4192 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4197 Convert \a rect to clip spans.
4199 void QClipData::setClipRect(const QRect &rect)
4201 if (hasRectClip && rect == clipRect)
4204 // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4206 hasRegionClip = false;
4210 xmax = rect.x() + rect.width();
4211 ymin = qMin(rect.y(), clipSpanHeight);
4212 ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4219 // qDebug() << xmin << xmax << ymin << ymax;
4223 Convert \a region to clip spans.
4225 void QClipData::setClipRegion(const QRegion ®ion)
4227 if (region.rectCount() == 1) {
4228 setClipRect(region.rects().at(0));
4232 hasRegionClip = true;
4233 hasRectClip = false;
4234 clipRegion = region;
4236 { // set bounding rect
4237 const QRect rect = region.boundingRect();
4239 xmax = rect.x() + rect.width();
4241 ymax = rect.y() + rect.height();
4253 spans must be sorted on y
4255 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4256 const QSpan *spans, const QSpan *end,
4257 QSpan **outSpans, int available)
4259 const_cast<QClipData *>(clip)->initialize();
4261 QSpan *out = *outSpans;
4263 const QSpan *clipSpans = clip->m_spans + *currentClip;
4264 const QSpan *clipEnd = clip->m_spans + clip->count;
4266 while (available && spans < end ) {
4267 if (clipSpans >= clipEnd) {
4271 if (clipSpans->y > spans->y) {
4275 if (spans->y != clipSpans->y) {
4276 if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4277 clipSpans = clip->m_clipLines[spans->y].spans;
4282 Q_ASSERT(spans->y == clipSpans->y);
4285 int sx2 = sx1 + spans->len;
4286 int cx1 = clipSpans->x;
4287 int cx2 = cx1 + clipSpans->len;
4289 if (cx1 < sx1 && cx2 < sx1) {
4292 } else if (sx1 < cx1 && sx2 < cx1) {
4296 int x = qMax(sx1, cx1);
4297 int len = qMin(sx2, cx2) - x;
4299 out->x = qMax(sx1, cx1);
4300 out->len = qMin(sx2, cx2) - out->x;
4302 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4314 *currentClip = clipSpans - clip->m_spans;
4318 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4320 // qDebug() << "qt_span_fill_clipped" << spanCount;
4321 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4323 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4325 const int NSPANS = 256;
4326 QSpan cspans[NSPANS];
4327 int currentClip = 0;
4328 const QSpan *end = spans + spanCount;
4329 while (spans < end) {
4330 QSpan *clipped = cspans;
4331 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4332 // qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4333 // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4335 if (clipped - cspans)
4336 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4342 Clip spans to \a{clip}-rectangle.
4343 Returns number of unclipped spans
4345 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4348 const short minx = clip.left();
4349 const short miny = clip.top();
4350 const short maxx = clip.right();
4351 const short maxy = clip.bottom();
4354 for (int i = 0; i < numSpans; ++i) {
4355 if (spans[i].y > maxy)
4357 if (spans[i].y < miny
4358 || spans[i].x > maxx
4359 || spans[i].x + spans[i].len <= minx) {
4362 if (spans[i].x < minx) {
4363 spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4366 spans[n].x = spans[i].x;
4367 spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4369 if (spans[n].len == 0)
4371 spans[n].y = spans[i].y;
4372 spans[n].coverage = spans[i].coverage;
4379 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4382 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4383 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4385 Q_ASSERT(fillData->clip);
4386 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4388 // hw: check if this const_cast<> is safe!!!
4389 count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4390 fillData->clip->clipRect);
4392 fillData->unclipped_blend(count, spans, fillData);
4395 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4397 ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4399 // qDebug() << " qt_span_clip: " << count << clipData->operation;
4400 // for (int i = 0; i < qMin(count, 10); ++i) {
4401 // qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4404 switch (clipData->operation) {
4406 case Qt::IntersectClip:
4408 QClipData *newClip = clipData->newClip;
4409 newClip->initialize();
4411 int currentClip = 0;
4412 const QSpan *end = spans + count;
4413 while (spans < end) {
4414 QSpan *newspans = newClip->m_spans + newClip->count;
4415 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4416 &newspans, newClip->allocated - newClip->count);
4417 newClip->count = newspans - newClip->m_spans;
4419 newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4420 newClip->allocated *= 2;
4427 case Qt::ReplaceClip:
4428 clipData->newClip->appendSpans(spans, count);
4436 QImage QRasterBuffer::bufferImage() const
4438 QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4440 for (int y = 0; y < m_height; ++y) {
4441 uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4443 for (int x=0; x<m_width; ++x) {
4444 uint argb = span[x];
4445 image.setPixel(x, y, argb);
4453 void QRasterBuffer::flushToARGBImage(QImage *target) const
4455 int w = qMin(m_width, target->width());
4456 int h = qMin(m_height, target->height());
4458 for (int y=0; y<h; ++y) {
4459 uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4460 QRgb *dest = (QRgb *) target->scanLine(y);
4461 for (int x=0; x<w; ++x) {
4462 QRgb pixel = sourceLine[x];
4463 int alpha = qAlpha(pixel);
4467 dest[x] = (alpha << 24)
4468 | ((255*qRed(pixel)/alpha) << 16)
4469 | ((255*qGreen(pixel)/alpha) << 8)
4470 | ((255*qBlue(pixel)/alpha) << 0);
4477 class QGradientCache
4481 inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4482 stops(s), opacity(op), interpolationMode(mode) {}
4483 uint buffer[GRADIENT_STOPTABLE_SIZE];
4484 QGradientStops stops;
4486 QGradient::InterpolationMode interpolationMode;
4489 typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4492 inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4493 quint64 hash_val = 0;
4495 QGradientStops stops = gradient.stops();
4496 for (int i = 0; i < stops.size() && i <= 2; i++)
4497 hash_val += stops[i].second.rgba();
4499 QMutexLocker lock(&mutex);
4500 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4502 if (it == cache.constEnd())
4503 return addCacheElement(hash_val, gradient, opacity);
4506 const CacheInfo &cache_info = it.value();
4507 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4508 return cache_info.buffer;
4510 } while (it != cache.constEnd() && it.key() == hash_val);
4511 // an exact match for these stops and opacity was not found, create new cache
4512 return addCacheElement(hash_val, gradient, opacity);
4516 inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4518 inline int maxCacheSize() const { return 60; }
4519 inline void generateGradientColorTable(const QGradient& g,
4521 int size, int opacity) const;
4522 uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4523 if (cache.size() == maxCacheSize()) {
4524 // may remove more than 1, but OK
4525 cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4527 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4528 generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4529 return cache.insert(hash_val, cache_entry).value().buffer;
4532 QGradientColorTableHash cache;
4536 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4538 QGradientStops stops = gradient.stops();
4539 int stopCount = stops.count();
4540 Q_ASSERT(stopCount > 0);
4542 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4544 if (stopCount == 2) {
4545 uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4546 uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4548 qreal first_stop = stops[0].first;
4549 qreal second_stop = stops[1].first;
4551 if (second_stop < first_stop) {
4552 qSwap(first_color, second_color);
4553 qSwap(first_stop, second_stop);
4556 if (colorInterpolation) {
4557 first_color = PREMUL(first_color);
4558 second_color = PREMUL(second_color);
4561 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4562 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4564 uint red_first = qRed(first_color) << 16;
4565 uint green_first = qGreen(first_color) << 16;
4566 uint blue_first = qBlue(first_color) << 16;
4567 uint alpha_first = qAlpha(first_color) << 16;
4569 uint red_second = qRed(second_color) << 16;
4570 uint green_second = qGreen(second_color) << 16;
4571 uint blue_second = qBlue(second_color) << 16;
4572 uint alpha_second = qAlpha(second_color) << 16;
4575 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4576 if (colorInterpolation)
4577 colorTable[i] = first_color;
4579 colorTable[i] = PREMUL(first_color);
4582 if (i < second_index) {
4583 qreal reciprocal = qreal(1) / (second_index - first_index);
4585 int red_delta = qRound(int(red_second - red_first) * reciprocal);
4586 int green_delta = qRound(int(green_second - green_first) * reciprocal);
4587 int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4588 int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4591 red_first += 1 << 15;
4592 green_first += 1 << 15;
4593 blue_first += 1 << 15;
4594 alpha_first += 1 << 15;
4596 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4597 red_first += red_delta;
4598 green_first += green_delta;
4599 blue_first += blue_delta;
4600 alpha_first += alpha_delta;
4602 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4603 | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4605 if (colorInterpolation)
4606 colorTable[i] = color;
4608 colorTable[i] = PREMUL(color);
4612 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4613 if (colorInterpolation)
4614 colorTable[i] = second_color;
4616 colorTable[i] = PREMUL(second_color);
4622 uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4623 if (stopCount == 1) {
4624 current_color = PREMUL(current_color);
4625 for (int i = 0; i < size; ++i)
4626 colorTable[i] = current_color;
4630 // The position where the gradient begins and ends
4631 qreal begin_pos = stops[0].first;
4632 qreal end_pos = stops[stopCount-1].first;
4634 int pos = 0; // The position in the color table.
4637 qreal incr = 1 / qreal(size); // the double increment.
4638 qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4640 // Up to first point
4641 colorTable[pos++] = PREMUL(current_color);
4642 while (dpos <= begin_pos) {
4643 colorTable[pos] = colorTable[pos - 1];
4648 int current_stop = 0; // We always interpolate between current and current + 1.
4650 qreal t; // position between current left and right stops
4651 qreal t_delta; // the t increment per entry in the color table
4653 if (dpos < end_pos) {
4655 while (dpos > stops[current_stop+1].first)
4658 if (current_stop != 0)
4659 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4660 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4662 if (colorInterpolation) {
4663 current_color = PREMUL(current_color);
4664 next_color = PREMUL(next_color);
4667 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4668 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4669 t = (dpos - stops[current_stop].first) * c;
4673 Q_ASSERT(current_stop < stopCount);
4675 int dist = qRound(t);
4676 int idist = 256 - dist;
4678 if (colorInterpolation)
4679 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4681 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4686 if (dpos >= end_pos)
4692 while (dpos > stops[current_stop+skip+1].first)
4696 current_stop += skip;
4698 current_color = next_color;
4700 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4701 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4703 if (colorInterpolation) {
4705 current_color = PREMUL(current_color);
4706 next_color = PREMUL(next_color);
4709 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4710 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4711 t = (dpos - stops[current_stop].first) * c;
4718 current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4719 while (pos < size - 1) {
4720 colorTable[pos] = current_color;
4724 // Make sure the last color stop is represented at the end of the table
4725 colorTable[size - 1] = current_color;
4728 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4731 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4735 rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4740 m11 = m22 = m33 = 1.;
4741 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4742 clip = pe ? pe->d_func()->clip() : 0;
4745 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4747 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4749 Qt::BrushStyle brushStyle = qbrush_style(brush);
4750 switch (brushStyle) {
4751 case Qt::SolidPattern: {
4753 QColor c = qbrush_color(brush);
4754 QRgb rgba = c.rgba();
4755 solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4756 if ((solid.color & 0xff000000) == 0
4757 && compositionMode == QPainter::CompositionMode_SourceOver) {
4763 case Qt::LinearGradientPattern:
4765 type = LinearGradient;
4766 const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4767 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4768 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4769 gradient.spread = g->spread();
4771 QLinearGradientData &linearData = gradient.linear;
4773 linearData.origin.x = g->start().x();
4774 linearData.origin.y = g->start().y();
4775 linearData.end.x = g->finalStop().x();
4776 linearData.end.y = g->finalStop().y();
4780 case Qt::RadialGradientPattern:
4782 type = RadialGradient;
4783 const QRadialGradient *g = static_cast<const QRadialGradient *>(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 QRadialGradientData &radialData = gradient.radial;
4790 QPointF center = g->center();
4791 radialData.center.x = center.x();
4792 radialData.center.y = center.y();
4793 radialData.center.radius = g->centerRadius();
4794 QPointF focal = g->focalPoint();
4795 radialData.focal.x = focal.x();
4796 radialData.focal.y = focal.y();
4797 radialData.focal.radius = g->focalRadius();
4801 case Qt::ConicalGradientPattern:
4803 type = ConicalGradient;
4804 const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4805 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4806 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4807 gradient.spread = QGradient::RepeatSpread;
4809 QConicalGradientData &conicalData = gradient.conical;
4811 QPointF center = g->center();
4812 conicalData.center.x = center.x();
4813 conicalData.center.y = center.y();
4814 conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4818 case Qt::Dense1Pattern:
4819 case Qt::Dense2Pattern:
4820 case Qt::Dense3Pattern:
4821 case Qt::Dense4Pattern:
4822 case Qt::Dense5Pattern:
4823 case Qt::Dense6Pattern:
4824 case Qt::Dense7Pattern:
4825 case Qt::HorPattern:
4826 case Qt::VerPattern:
4827 case Qt::CrossPattern:
4828 case Qt::BDiagPattern:
4829 case Qt::FDiagPattern:
4830 case Qt::DiagCrossPattern:
4833 tempImage = new QImage();
4834 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4835 initTexture(tempImage, alpha, QTextureData::Tiled);
4837 case Qt::TexturePattern:
4840 tempImage = new QImage();
4842 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4843 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4845 *tempImage = brush.textureImage();
4846 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4854 adjustSpanMethods();
4857 void QSpanData::adjustSpanMethods()
4867 unclipped_blend = 0;
4870 unclipped_blend = rasterBuffer->drawHelper->blendColor;
4871 bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4872 alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4873 alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4874 fillRect = rasterBuffer->drawHelper->fillRect;
4876 case LinearGradient:
4877 case RadialGradient:
4878 case ConicalGradient:
4879 unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4883 #ifndef QT_NO_RASTERCALLBACKS
4884 if (!rasterBuffer->buffer())
4885 unclipped_blend = qBlendTextureCallback;
4888 unclipped_blend = qBlendTexture;
4890 unclipped_blend = qBlendTexture;
4892 if (!texture.imageData)
4893 unclipped_blend = 0;
4898 if (!unclipped_blend) {
4901 blend = unclipped_blend;
4902 } else if (clip->hasRectClip) {
4903 blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4905 blend = qt_span_fill_clipped;
4909 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4912 // make sure we round off correctly in qdrawhelper.cpp
4913 delta.translate(1.0 / 65536, 1.0 / 65536);
4915 QTransform inv = (delta * matrix).inverted();
4928 const bool affine = !m13 && !m23;
4929 fast_matrix = affine
4930 && m11 * m11 + m21 * m21 < 1e4
4931 && m12 * m12 + m22 * m22 < 1e4
4935 adjustSpanMethods();
4938 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4940 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4942 const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4943 if (!d || d->height == 0) {
4944 texture.imageData = 0;
4951 texture.bytesPerLine = 0;
4952 texture.format = QImage::Format_Invalid;
4953 texture.colorTable = 0;
4954 texture.hasAlpha = alpha != 256;
4956 texture.imageData = d->data;
4957 texture.width = d->width;
4958 texture.height = d->height;
4960 if (sourceRect.isNull()) {
4963 texture.x2 = texture.width;
4964 texture.y2 = texture.height;
4966 texture.x1 = sourceRect.x();
4967 texture.y1 = sourceRect.y();
4968 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4969 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4972 texture.bytesPerLine = d->bytes_per_line;
4974 texture.format = d->format;
4975 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4976 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4978 texture.const_alpha = alpha;
4979 texture.type = _type;
4981 adjustSpanMethods();
4986 \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4989 Draws the first \a pointCount points in the buffer \a points
4991 The default implementation converts the first \a pointCount QPoints in \a points
4992 to QPointFs and calls the floating point version of drawPoints.
4996 \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
4999 Reimplement this function to draw the largest ellipse that can be
5000 contained within rectangle \a rect.
5003 #ifdef QT_DEBUG_DRAW
5004 void dumpClip(int width, int height, const QClipData *clip)
5006 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5007 clipImg.fill(0xffff0000);
5014 ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5016 for (int i = 0; i < clip->count; ++i) {
5017 const QSpan *span = ((QClipData *) clip)->spans() + i;
5018 for (int j = 0; j < span->len; ++j)
5019 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5020 x0 = qMin(x0, int(span->x));
5021 x1 = qMax(x1, int(span->x + span->len - 1));
5023 y0 = qMin(y0, int(span->y));
5024 y1 = qMax(y1, int(span->y));
5027 static int counter = 0;
5034 fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5035 clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));