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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
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);
2010 for (int i=0; i<count; i+=2) {
2011 fpoints[i] = ((int *) points)[i+1];
2012 fpoints[i+1] = ((int *) points)[i];
2015 for (int i=0; i<count; ++i)
2016 fpoints[i] = ((int *) points)[i];
2018 QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2020 if (s->flags.fast_pen) {
2021 QCosmeticStroker stroker(s, d->deviceRect);
2022 stroker.drawPath(vp);
2024 QPaintEngineEx::stroke(vp, s->lastPen);
2032 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2034 #ifdef QT_DEBUG_DRAW
2035 qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2038 QPixmapData *pd = pixmap.pixmapData();
2039 if (pd->classId() == QPixmapData::RasterClass) {
2040 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2041 if (image.depth() == 1) {
2042 Q_D(QRasterPaintEngine);
2043 QRasterPaintEngineState *s = state();
2044 if (s->matrix.type() <= QTransform::TxTranslate) {
2046 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2048 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2051 QRasterPaintEngine::drawImage(pos, image);
2054 const QImage image = pixmap.toImage();
2055 if (pixmap.depth() == 1) {
2056 Q_D(QRasterPaintEngine);
2057 QRasterPaintEngineState *s = state();
2058 if (s->matrix.type() <= QTransform::TxTranslate) {
2060 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2062 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2065 QRasterPaintEngine::drawImage(pos, image);
2073 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2075 #ifdef QT_DEBUG_DRAW
2076 qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2079 QPixmapData* pd = pixmap.pixmapData();
2080 if (pd->classId() == QPixmapData::RasterClass) {
2081 const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2082 if (image.depth() == 1) {
2083 Q_D(QRasterPaintEngine);
2084 QRasterPaintEngineState *s = state();
2085 if (s->matrix.type() <= QTransform::TxTranslate
2086 && r.size() == sr.size()
2087 && r.size() == pixmap.size()) {
2089 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2092 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2095 drawImage(r, image, sr);
2098 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2099 const QImage image = pd->toImage(clippedSource);
2100 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2101 if (image.depth() == 1) {
2102 Q_D(QRasterPaintEngine);
2103 QRasterPaintEngineState *s = state();
2104 if (s->matrix.type() <= QTransform::TxTranslate
2105 && r.size() == sr.size()
2106 && r.size() == pixmap.size()) {
2108 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2111 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2114 drawImage(r, image, translatedSource);
2119 // assumes that rect has positive width and height
2120 static inline const QRect toRect_normalized(const QRectF &rect)
2122 const int x = qRound(rect.x());
2123 const int y = qRound(rect.y());
2124 const int w = int(rect.width() + qreal(0.5));
2125 const int h = int(rect.height() + qreal(0.5));
2127 return QRect(x, y, w, h);
2130 static inline int fast_ceil_positive(const qreal &v)
2132 const int iv = int(v);
2139 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2141 const int xmin = int(rect.x());
2142 const int xmax = int(fast_ceil_positive(rect.right()));
2143 const int ymin = int(rect.y());
2144 const int ymax = int(fast_ceil_positive(rect.bottom()));
2145 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2151 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2153 #ifdef QT_DEBUG_DRAW
2154 qDebug() << " - QRasterPaintEngine::drawImage(), p=" << p << " image=" << img.size() << "depth=" << img.depth();
2157 Q_D(QRasterPaintEngine);
2158 QRasterPaintEngineState *s = state();
2160 if (s->matrix.type() > QTransform::TxTranslate) {
2161 drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2163 QRectF(0, 0, img.width(), img.height()));
2166 const QClipData *clip = d->clip();
2167 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2169 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2170 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2173 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2175 } else if (clip->hasRectClip) {
2176 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2184 d->image_filler.clip = clip;
2185 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2186 if (!d->image_filler.blend)
2188 d->image_filler.dx = -pt.x();
2189 d->image_filler.dy = -pt.y();
2190 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2192 fillRect_normalized(rr, &d->image_filler, d);
2197 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2199 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2210 inline RotationType qRotationType(const QTransform &transform)
2212 QTransform::TransformationType type = transform.type();
2214 if (type > QTransform::TxRotate)
2217 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2218 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2221 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2222 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2225 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2226 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2232 inline bool isPixelAligned(const QRectF &rect) {
2233 return QRectF(rect.toRect()) == rect;
2240 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2241 Qt::ImageConversionFlags)
2243 #ifdef QT_DEBUG_DRAW
2244 qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2250 Q_D(QRasterPaintEngine);
2251 QRasterPaintEngineState *s = state();
2252 int sr_l = qFloor(sr.left());
2253 int sr_r = qCeil(sr.right()) - 1;
2254 int sr_t = qFloor(sr.top());
2255 int sr_b = qCeil(sr.bottom()) - 1;
2257 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2258 QTransform old = s->matrix;
2260 // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2261 QRgb color = img.pixel(sr_l, sr_t);
2262 switch (img.format()) {
2263 case QImage::Format_ARGB32_Premultiplied:
2264 case QImage::Format_ARGB8565_Premultiplied:
2265 case QImage::Format_ARGB6666_Premultiplied:
2266 case QImage::Format_ARGB8555_Premultiplied:
2267 case QImage::Format_ARGB4444_Premultiplied:
2268 // Combine premultiplied color with the opacity set on the painter.
2269 d->solid_color_filler.solid.color =
2270 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2271 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2274 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2278 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2279 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2283 d->solid_color_filler.clip = d->clip();
2284 d->solid_color_filler.adjustSpanMethods();
2285 fillRect(r, &d->solid_color_filler);
2291 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2293 const QClipData *clip = d->clip();
2295 if (s->matrix.type() > QTransform::TxTranslate
2297 && (!clip || clip->hasRectClip)
2298 && s->intOpacity == 256
2299 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2300 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2301 && d->rasterBuffer->format == img.format()
2302 && (d->rasterBuffer->format == QImage::Format_RGB16
2303 || d->rasterBuffer->format == QImage::Format_RGB32
2304 || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2305 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2307 RotationType rotationType = qRotationType(s->matrix);
2309 if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2310 QRectF transformedTargetRect = s->matrix.mapRect(r);
2312 if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2313 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2315 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2316 if (clippedTransformedTargetRect.isNull())
2319 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2321 QRect clippedSourceRect
2322 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2323 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2325 uint dbpl = d->rasterBuffer->bytesPerLine();
2326 uint sbpl = img.bytesPerLine();
2328 uchar *dst = d->rasterBuffer->buffer();
2329 uint bpp = img.depth() >> 3;
2331 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2332 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2334 uint cw = clippedSourceRect.width();
2335 uint ch = clippedSourceRect.height();
2337 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2344 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2346 QRectF targetBounds = s->matrix.mapRect(r);
2347 bool exceedsPrecision = targetBounds.width() > 0xffff
2348 || targetBounds.height() > 0xffff;
2350 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2351 if (s->matrix.type() > QTransform::TxScale) {
2352 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2353 if (func && (!clip || clip->hasRectClip)) {
2354 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2355 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2356 s->matrix, s->intOpacity);
2360 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2361 if (func && (!clip || clip->hasRectClip)) {
2362 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2363 img.bits(), img.bytesPerLine(),
2364 qt_mapRect_non_normalizing(r, s->matrix), sr,
2365 !clip ? d->deviceRect : clip->clipRect,
2372 QTransform copy = s->matrix;
2373 copy.translate(r.x(), r.y());
2375 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2376 copy.translate(-sr.x(), -sr.y());
2378 d->image_filler_xform.clip = clip;
2379 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2380 if (!d->image_filler_xform.blend)
2382 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2384 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2385 QRectF rr = s->matrix.mapRect(r);
2387 const int x1 = qRound(rr.x());
2388 const int y1 = qRound(rr.y());
2389 const int x2 = qRound(rr.right());
2390 const int y2 = qRound(rr.bottom());
2392 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2396 #ifdef QT_FAST_SPANS
2398 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2399 d->initializeRasterizer(&d->image_filler_xform);
2400 d->rasterizer->setAntialiased(s->flags.antialiased);
2402 const QRectF &rect = r.normalized();
2403 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2404 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2406 if (s->flags.tx_noshear)
2407 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2409 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2415 QTransform m = s->matrix;
2416 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2417 m.m21(), m.m22(), m.m23(),
2418 m.m31(), m.m32(), m.m33());
2419 fillPath(path, &d->image_filler_xform);
2422 if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2423 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2425 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2427 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2429 } else if (clip->hasRectClip) {
2430 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2436 d->image_filler.clip = clip;
2437 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2438 if (!d->image_filler.blend)
2440 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2441 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2444 rr.translate(s->matrix.dx(), s->matrix.dy());
2446 const int x1 = qRound(rr.x());
2447 const int y1 = qRound(rr.y());
2448 const int x2 = qRound(rr.right());
2449 const int y2 = qRound(rr.bottom());
2451 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2458 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2460 #ifdef QT_DEBUG_DRAW
2461 qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2463 Q_D(QRasterPaintEngine);
2464 QRasterPaintEngineState *s = state();
2468 QPixmapData *pd = pixmap.pixmapData();
2469 if (pd->classId() == QPixmapData::RasterClass) {
2470 image = static_cast<QRasterPixmapData *>(pd)->image;
2472 image = pixmap.toImage();
2475 if (image.depth() == 1)
2476 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2478 if (s->matrix.type() > QTransform::TxTranslate) {
2479 QTransform copy = s->matrix;
2480 copy.translate(r.x(), r.y());
2481 copy.translate(-sr.x(), -sr.y());
2482 d->image_filler_xform.clip = d->clip();
2483 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2484 if (!d->image_filler_xform.blend)
2486 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2488 #ifdef QT_FAST_SPANS
2490 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2491 d->initializeRasterizer(&d->image_filler_xform);
2492 d->rasterizer->setAntialiased(s->flags.antialiased);
2494 const QRectF &rect = r.normalized();
2495 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2496 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2497 if (s->flags.tx_noshear)
2498 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2500 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2506 fillPath(path, &d->image_filler_xform);
2508 d->image_filler.clip = d->clip();
2510 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2511 if (!d->image_filler.blend)
2513 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2514 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2517 rr.translate(s->matrix.dx(), s->matrix.dy());
2518 fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2524 static inline bool monoVal(const uchar* s, int x)
2526 return (s[x>>3] << (x&7)) & 0x80;
2532 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2534 Q_D(QRasterPaintEngine);
2535 QRasterPaintEngineState *s = state();
2537 if (!s->penData.blend)
2540 QRasterBuffer *rb = d->rasterBuffer.data();
2542 const QRect rect(rx, ry, w, h);
2543 const QClipData *clip = d->clip();
2544 bool unclipped = false;
2546 // inlined QRect::intersects
2547 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2548 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2550 if (clip->hasRectClip) {
2551 unclipped = rx > clip->xmin
2552 && rx + w < clip->xmax
2554 && ry + h < clip->ymax;
2560 // inlined QRect::intersects
2561 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2562 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2566 // inlined QRect::contains
2567 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2568 && rect.top() >= 0 && rect.bottom() < rb->height();
2570 unclipped = contains && d->isUnclipped_normalized(rect);
2573 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2574 const uchar * scanline = static_cast<const uchar *>(src);
2576 if (s->flags.fast_text) {
2579 if (s->penData.bitmapBlit) {
2580 s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2581 scanline, w, h, bpl);
2584 } else if (depth == 8) {
2585 if (s->penData.alphamapBlit) {
2586 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2587 scanline, w, h, bpl, 0);
2590 } else if (depth == 32) {
2591 // (A)RGB Alpha mask where the alpha component is not used.
2592 if (s->penData.alphaRGBBlit) {
2593 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2594 (const uint *) scanline, w, h, bpl / 4, 0);
2598 } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2599 // (A)RGB Alpha mask where the alpha component is not used.
2601 int nx = qMax(0, rx);
2602 int ny = qMax(0, ry);
2604 // Move scanline pointer to compensate for moved x and y
2605 int xdiff = nx - rx;
2606 int ydiff = ny - ry;
2607 scanline += ydiff * bpl;
2608 scanline += xdiff * (depth == 32 ? 4 : 1);
2613 if (nx + w > d->rasterBuffer->width())
2614 w = d->rasterBuffer->width() - nx;
2615 if (ny + h > d->rasterBuffer->height())
2616 h = d->rasterBuffer->height() - ny;
2621 if (depth == 8 && s->penData.alphamapBlit) {
2622 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2623 scanline, w, h, bpl, clip);
2624 } else if (depth == 32 && s->penData.alphaRGBBlit) {
2625 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2626 (const uint *) scanline, w, h, bpl / 4, clip);
2641 scanline += bpl * y0;
2645 w = qMin(w, rb->width() - qMax(0, rx));
2646 h = qMin(h, rb->height() - qMax(0, ry));
2648 if (w <= 0 || h <= 0)
2651 const int NSPANS = 256;
2652 QSpan spans[NSPANS];
2655 const int x1 = x0 + w;
2656 const int y1 = y0 + h;
2659 for (int y = y0; y < y1; ++y) {
2660 for (int x = x0; x < x1; ) {
2661 if (!monoVal(scanline, x)) {
2666 if (current == NSPANS) {
2667 blend(current, spans, &s->penData);
2670 spans[current].x = x + rx;
2671 spans[current].y = y + ry;
2672 spans[current].coverage = 255;
2675 // extend span until we find a different one.
2676 while (x < x1 && monoVal(scanline, x)) {
2680 spans[current].len = len;
2685 } else if (depth == 8) {
2686 for (int y = y0; y < y1; ++y) {
2687 for (int x = x0; x < x1; ) {
2688 // Skip those with 0 coverage
2689 if (scanline[x] == 0) {
2694 if (current == NSPANS) {
2695 blend(current, spans, &s->penData);
2698 int coverage = scanline[x];
2699 spans[current].x = x + rx;
2700 spans[current].y = y + ry;
2701 spans[current].coverage = coverage;
2705 // extend span until we find a different one.
2706 while (x < x1 && scanline[x] == coverage) {
2710 spans[current].len = len;
2715 } else { // 32-bit alpha...
2716 uint *sl = (uint *) src;
2717 for (int y = y0; y < y1; ++y) {
2718 for (int x = x0; x < x1; ) {
2719 // Skip those with 0 coverage
2720 if ((sl[x] & 0x00ffffff) == 0) {
2725 if (current == NSPANS) {
2726 blend(current, spans, &s->penData);
2729 uint rgbCoverage = sl[x];
2730 int coverage = qGreen(rgbCoverage);
2731 spans[current].x = x + rx;
2732 spans[current].y = y + ry;
2733 spans[current].coverage = coverage;
2737 // extend span until we find a different one.
2738 while (x < x1 && sl[x] == rgbCoverage) {
2742 spans[current].len = len;
2745 sl += bpl / sizeof(uint);
2748 // qDebug() << "alphaPenBlt: num spans=" << current
2749 // << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2750 // Call span func for current set of spans.
2752 blend(current, spans, &s->penData);
2755 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2756 const QFixedPoint *positions, QFontEngine *fontEngine)
2758 Q_D(QRasterPaintEngine);
2759 QRasterPaintEngineState *s = state();
2761 #if !defined(QT_NO_FREETYPE)
2762 if (fontEngine->type() == QFontEngine::Freetype) {
2763 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2764 QFontEngineFT::GlyphFormat neededFormat =
2765 painter()->device()->devType() == QInternal::Widget
2766 ? fe->defaultGlyphFormat()
2767 : QFontEngineFT::Format_A8;
2769 if (d_func()->mono_surface
2770 || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2772 neededFormat = QFontEngineFT::Format_Mono;
2774 if (neededFormat == QFontEngineFT::Format_None)
2775 neededFormat = QFontEngineFT::Format_A8;
2777 QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2778 if (s->matrix.type() >= QTransform::TxScale) {
2779 if (s->matrix.isAffine())
2780 gset = fe->loadTransformedGlyphSet(s->matrix);
2785 if (!gset || gset->outline_drawing
2786 || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2789 FT_Face lockedFace = 0;
2792 switch (neededFormat) {
2793 case QFontEngineFT::Format_Mono:
2796 case QFontEngineFT::Format_A8:
2799 case QFontEngineFT::Format_A32:
2807 for (int i = 0; i < numGlyphs; i++) {
2808 QFixed spp = fe->subPixelPositionForX(positions[i].x);
2809 QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2811 if (!glyph || glyph->format != neededFormat) {
2813 lockedFace = fe->lockFace();
2814 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2817 if (!glyph || !glyph->data)
2821 switch (neededFormat) {
2822 case QFontEngineFT::Format_Mono:
2823 pitch = ((glyph->width + 31) & ~31) >> 3;
2825 case QFontEngineFT::Format_A8:
2826 pitch = (glyph->width + 3) & ~3;
2828 case QFontEngineFT::Format_A32:
2829 pitch = glyph->width * 4;
2836 alphaPenBlt(glyph->data, pitch, depth,
2837 qFloor(positions[i].x) + glyph->x,
2838 qFloor(positions[i].y) - glyph->y,
2839 glyph->width, glyph->height);
2846 QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2848 QImageTextureGlyphCache *cache =
2849 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2851 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2852 fontEngine->setGlyphCache(0, cache);
2855 cache->populate(fontEngine, numGlyphs, glyphs, positions);
2856 cache->fillInPendingGlyphs();
2858 const QImage &image = cache->image();
2859 int bpl = image.bytesPerLine();
2861 int depth = image.depth();
2865 leftShift = 2; // multiply by 4
2866 else if (depth == 1)
2867 rightShift = 3; // divide by 8
2869 int margin = cache->glyphMargin();
2870 const uchar *bits = image.bits();
2871 for (int i=0; i<numGlyphs; ++i) {
2873 QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2874 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2875 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2879 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2880 int y = qFloor(positions[i].y) - c.baseLineY - margin;
2882 // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2885 // c.baseLineX, c.baseLineY,
2888 // positions[i].x.toInt(), positions[i].y.toInt());
2890 alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2896 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2897 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2899 Q_D(QRasterPaintEngine);
2900 QRasterPaintEngineState *s = state();
2902 QFontEngine *fontEngine = ti.fontEngine;
2903 if (fontEngine->type() != QFontEngine::S60FontEngine) {
2904 QPaintEngineEx::drawTextItem(p, ti);
2908 QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2910 QVarLengthArray<QFixedPoint> positions;
2911 QVarLengthArray<glyph_t> glyphs;
2912 QTransform matrix = s->matrix;
2913 matrix.translate(p.x(), p.y());
2914 if (matrix.type() == QTransform::TxScale)
2915 fe->setFontScale(matrix.m11());
2916 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2918 for (int i=0; i<glyphs.size(); ++i) {
2919 TOpenFontCharMetrics tmetrics;
2920 const TUint8 *glyphBitmapBytes;
2921 TSize glyphBitmapSize;
2922 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2923 const int x = qFloor(positions[i].x + tmetrics.HorizBearingX());
2924 const int y = qFloor(positions[i].y - tmetrics.HorizBearingY());
2925 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2928 if (matrix.type() == QTransform::TxScale)
2929 fe->setFontScale(1.0);
2933 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2936 * Returns true if the rectangle is completely within the current clip
2937 * state of the paint engine.
2939 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2941 const QClipData *cl = clip();
2943 // inline contains() for performance (we know the rects are normalized)
2944 const QRect &r1 = deviceRect;
2945 return (r.left() >= r1.left() && r.right() <= r1.right()
2946 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2950 if (cl->hasRectClip) {
2951 // currently all painting functions clips to deviceRect internally
2952 if (cl->clipRect == deviceRect)
2955 // inline contains() for performance (we know the rects are normalized)
2956 const QRect &r1 = cl->clipRect;
2957 return (r.left() >= r1.left() && r.right() <= r1.right()
2958 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2960 return qt_region_strictContains(cl->clipRegion, r);
2964 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2967 Q_Q(const QRasterPaintEngine);
2968 const QRasterPaintEngineState *s = q->state();
2969 const QClipData *cl = clip();
2971 QRect r = rect.normalized();
2972 // inline contains() for performance (we know the rects are normalized)
2973 const QRect &r1 = deviceRect;
2974 return (r.left() >= r1.left() && r.right() <= r1.right()
2975 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2979 // currently all painting functions that call this function clip to deviceRect internally
2980 if (cl->hasRectClip && cl->clipRect == deviceRect)
2983 if (s->flags.antialiased)
2986 QRect r = rect.normalized();
2988 r.setX(r.x() - penWidth);
2989 r.setY(r.y() - penWidth);
2990 r.setWidth(r.width() + 2 * penWidth);
2991 r.setHeight(r.height() + 2 * penWidth);
2994 if (cl->hasRectClip) {
2995 // inline contains() for performance (we know the rects are normalized)
2996 const QRect &r1 = cl->clipRect;
2997 return (r.left() >= r1.left() && r.right() <= r1.right()
2998 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3000 return qt_region_strictContains(cl->clipRegion, r);
3004 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3007 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3011 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3012 const QSpanData *data) const
3014 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3018 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3019 const QSpanData *data) const
3021 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3027 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3032 QRasterPaintEngineState *s = state();
3034 QFontEngine *fontEngine = textItem->fontEngine();
3035 const qreal pixelSize = fontEngine->fontDef.pixelSize;
3036 if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) < 64 * 64) {
3037 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3040 QPaintEngineEx::drawStaticTextItem(textItem);
3047 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3049 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3050 QRasterPaintEngineState *s = state();
3052 #ifdef QT_DEBUG_DRAW
3053 Q_D(QRasterPaintEngine);
3054 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3055 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3062 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3064 bool drawCached = true;
3066 if (s->matrix.type() >= QTransform::TxProject)
3069 // don't try to cache huge fonts
3070 const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
3071 if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64)
3074 // ### Remove the TestFontEngine and Box engine crap, in these
3075 // ### cases we should delegate painting to the font engine
3078 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3079 QFontEngine::Type fontEngineType = ti.fontEngine->type();
3080 // qDebug() << "type" << fontEngineType << s->matrix.type();
3081 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
3082 || (s->matrix.type() <= QTransform::TxTranslate
3083 && (fontEngineType == QFontEngine::TestFontEngine
3084 || fontEngineType == QFontEngine::Box))) {
3088 if (s->matrix.type() > QTransform::TxTranslate)
3092 QRasterPaintEngineState *s = state();
3094 QVarLengthArray<QFixedPoint> positions;
3095 QVarLengthArray<glyph_t> glyphs;
3097 QTransform matrix = s->matrix;
3098 matrix.translate(p.x(), p.y());
3100 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3102 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3106 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3107 if (s->matrix.type() <= QTransform::TxTranslate
3108 || (s->matrix.type() == QTransform::TxScale
3109 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3110 drawGlyphsS60(p, ti);
3113 #else // Q_WS_WIN || Q_WS_MAC
3115 QFontEngine *fontEngine = ti.fontEngine;
3117 #if defined(Q_WS_QWS)
3118 if (fontEngine->type() == QFontEngine::Box) {
3119 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3123 if (s->matrix.type() < QTransform::TxScale
3124 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3125 || (fontEngine->type() == QFontEngine::Proxy
3126 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3128 fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3134 if (s->matrix.type() < QTransform::TxScale) {
3136 QVarLengthArray<QFixedPoint> positions;
3137 QVarLengthArray<glyph_t> glyphs;
3138 QTransform matrix = state()->transform();
3140 qreal _x = qFloor(p.x());
3141 qreal _y = qFloor(p.y());
3142 matrix.translate(_x, _y);
3144 fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3145 if (glyphs.size() == 0)
3148 for(int i = 0; i < glyphs.size(); i++) {
3149 QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3150 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3151 alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3152 qRound(positions[i].x + metrics.x),
3153 qRound(positions[i].y + metrics.y),
3154 img.width(), img.height());
3160 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3162 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3163 if (fontEngine->type() == QFontEngine::QPF2) {
3164 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3165 if (renderingEngine)
3166 fontEngine = renderingEngine;
3170 if (fontEngine->type() != QFontEngine::Freetype) {
3171 QPaintEngineEx::drawTextItem(p, ti);
3175 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3177 QTransform matrix = s->matrix;
3178 matrix.translate(p.x(), p.y());
3180 QVarLengthArray<QFixedPoint> positions;
3181 QVarLengthArray<glyph_t> glyphs;
3182 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3183 if (glyphs.size() == 0)
3186 if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3187 QPaintEngine::drawTextItem(p, ti);
3193 QPaintEngineEx::drawTextItem(p, ti);
3199 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3201 Q_D(QRasterPaintEngine);
3202 QRasterPaintEngineState *s = state();
3205 if (!s->penData.blend)
3208 if (!s->flags.fast_pen) {
3209 QPaintEngineEx::drawPoints(points, pointCount);
3213 QCosmeticStroker stroker(s, d->deviceRect);
3214 stroker.drawPoints(points, pointCount);
3218 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3220 Q_D(QRasterPaintEngine);
3221 QRasterPaintEngineState *s = state();
3224 if (!s->penData.blend)
3227 if (!s->flags.fast_pen) {
3228 QPaintEngineEx::drawPoints(points, pointCount);
3232 QCosmeticStroker stroker(s, d->deviceRect);
3233 stroker.drawPoints(points, pointCount);
3239 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3241 #ifdef QT_DEBUG_DRAW
3242 qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3244 Q_D(QRasterPaintEngine);
3245 QRasterPaintEngineState *s = state();
3248 if (!s->penData.blend)
3251 if (s->flags.fast_pen) {
3252 QCosmeticStroker stroker(s, d->deviceRect);
3253 for (int i=0; i<lineCount; ++i) {
3254 const QLine &l = lines[i];
3255 stroker.drawLine(l.p1(), l.p2());
3258 QPaintEngineEx::drawLines(lines, lineCount);
3262 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3268 Q_Q(QRasterPaintEngine);
3269 QRasterPaintEngineState *s = q->state();
3271 const QPen &pen = s->lastPen;
3272 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3273 const QVector<qreal> pattern = pen.dashPattern();
3275 qreal patternLength = 0;
3276 for (int i = 0; i < pattern.size(); ++i)
3277 patternLength += pattern.at(i);
3279 if (patternLength <= 0)
3282 qreal length = line.length();
3283 Q_ASSERT(length > 0);
3284 while (length > 0) {
3285 const bool rasterize = *inDash;
3286 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3289 if (dash >= length) {
3291 *dashOffset += dash / width;
3295 *inDash = !(*inDash);
3296 if (++*dashIndex >= pattern.size())
3303 if (rasterize && dash > 0)
3304 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3311 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3313 #ifdef QT_DEBUG_DRAW
3314 qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3316 Q_D(QRasterPaintEngine);
3317 QRasterPaintEngineState *s = state();
3320 if (!s->penData.blend)
3322 if (s->flags.fast_pen) {
3323 QCosmeticStroker stroker(s, d->deviceRect);
3324 for (int i=0; i<lineCount; ++i) {
3325 QLineF line = lines[i];
3326 stroker.drawLine(line.p1(), line.p2());
3329 QPaintEngineEx::drawLines(lines, lineCount);
3337 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3339 QPaintEngineEx::drawEllipse(rect);
3346 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3348 Q_D(QRasterPaintEngine);
3355 CGContextRef QRasterPaintEngine::getCGContext() const
3357 Q_D(const QRasterPaintEngine);
3358 return d->cgContext;
3366 void QRasterPaintEngine::setDC(HDC hdc) {
3367 Q_D(QRasterPaintEngine);
3374 HDC QRasterPaintEngine::getDC() const
3376 Q_D(const QRasterPaintEngine);
3383 void QRasterPaintEngine::releaseDC(HDC) const
3392 QPoint QRasterPaintEngine::coordinateOffset() const
3394 return QPoint(0, 0);
3398 Draws the given color \a spans with the specified \a color. The \a
3399 count parameter specifies the number of spans.
3401 The default implementation does nothing; reimplement this function
3402 to draw the given color \a spans with the specified \a color. Note
3403 that this function \e must be reimplemented if the framebuffer is
3406 \sa drawBufferSpan()
3408 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3409 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3414 qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3415 "a non memory-mapped device");
3419 \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3421 Draws the given \a buffer.
3423 The default implementation does nothing; reimplement this function
3424 to draw a buffer that contains more than one color. Note that this
3425 function \e must be reimplemented if the framebuffer is not
3428 The \a size parameter specifies the total size of the given \a
3429 buffer, while the \a length parameter specifies the number of
3430 pixels to draw. The buffer's position is given by (\a x, \a
3431 y). The provided \a alpha value is added to each pixel in the
3432 buffer when drawing.
3434 \sa drawColorSpans()
3436 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3437 int x, int y, int length, uint const_alpha)
3444 Q_UNUSED(const_alpha);
3445 qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3446 "a non memory-mapped device");
3450 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3455 Q_D(QRasterPaintEngine);
3457 Q_ASSERT(image.depth() == 1);
3459 const int spanCount = 256;
3460 QT_FT_Span spans[spanCount];
3464 int w = image.width();
3465 int h = image.height();
3466 int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3467 int ymin = qMax(qRound(pos.y()), 0);
3468 int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3469 int xmin = qMax(qRound(pos.x()), 0);
3471 int x_offset = xmin - qRound(pos.x());
3473 QImage::Format format = image.format();
3474 for (int y = ymin; y < ymax; ++y) {
3475 const uchar *src = image.scanLine(y - qRound(pos.y()));
3476 if (format == QImage::Format_MonoLSB) {
3477 for (int x = 0; x < xmax - xmin; ++x) {
3478 int src_x = x + x_offset;
3479 uchar pixel = src[src_x >> 3];
3484 if (pixel & (0x1 << (src_x & 7))) {
3485 spans[n].x = xmin + x;
3487 spans[n].coverage = 255;
3489 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3493 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3496 if (n == spanCount) {
3497 fg->blend(n, spans, fg);
3503 for (int x = 0; x < xmax - xmin; ++x) {
3504 int src_x = x + x_offset;
3505 uchar pixel = src[src_x >> 3];
3510 if (pixel & (0x80 >> (x & 7))) {
3511 spans[n].x = xmin + x;
3513 spans[n].coverage = 255;
3515 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3519 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3522 if (n == spanCount) {
3523 fg->blend(n, spans, fg);
3531 fg->blend(n, spans, fg);
3537 \enum QRasterPaintEngine::ClipType
3540 \value RectClip Indicates that the currently set clip is a single rectangle.
3541 \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3546 Returns the type of the clip currently set.
3548 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3550 Q_D(const QRasterPaintEngine);
3552 const QClipData *clip = d->clip();
3553 if (!clip || clip->hasRectClip)
3561 Returns the bounding rect of the currently set clip.
3563 QRect QRasterPaintEngine::clipBoundingRect() const
3565 Q_D(const QRasterPaintEngine);
3567 const QClipData *clip = d->clip();
3570 return d->deviceRect;
3572 if (clip->hasRectClip)
3573 return clip->clipRect;
3575 return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3578 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3580 Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3582 QVarLengthArray<short, 4096> buffer;
3584 QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3585 QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3586 result->initialize();
3588 for (int y = 0; y < c1->clipSpanHeight; ++y) {
3589 const QSpan *c1_spans = c1ClipLines[y].spans;
3590 int c1_count = c1ClipLines[y].count;
3591 const QSpan *c2_spans = c2ClipLines[y].spans;
3592 int c2_count = c2ClipLines[y].count;
3594 if (c1_count == 0 && c2_count == 0)
3596 if (c1_count == 0) {
3597 result->appendSpans(c2_spans, c2_count);
3599 } else if (c2_count == 0) {
3600 result->appendSpans(c1_spans, c1_count);
3604 // we need to merge the two
3606 // find required length
3607 int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3608 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3610 memset(buffer.data(), 0, buffer.size() * sizeof(short));
3612 // Fill with old spans.
3613 for (int i = 0; i < c1_count; ++i) {
3614 const QSpan *cs = c1_spans + i;
3615 for (int j=cs->x; j<cs->x + cs->len; ++j)
3616 buffer[j] = cs->coverage;
3619 // Fill with new spans
3620 for (int i = 0; i < c2_count; ++i) {
3621 const QSpan *cs = c2_spans + i;
3622 for (int j = cs->x; j < cs->x + cs->len; ++j) {
3623 buffer[j] += cs->coverage;
3624 if (buffer[j] > 255)
3632 // Skip to next span
3633 while (x < max && buffer[x] == 0) ++x;
3634 if (x >= max) break;
3637 int coverage = buffer[x];
3639 // Find length of span
3640 while (x < max && buffer[x] == coverage)
3643 result->appendSpan(sx, x - sx, y, coverage);
3648 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3650 Q_Q(QRasterPaintEngine);
3651 QRasterPaintEngineState *s = q->state();
3653 rasterizer->setAntialiased(s->flags.antialiased);
3655 QRect clipRect(deviceRect);
3657 // ### get from optimized rectbased QClipData
3659 const QClipData *c = clip();
3661 const QRect r(QPoint(c->xmin, c->ymin),
3662 QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3663 clipRect = clipRect.intersected(r);
3664 blend = data->blend;
3666 blend = data->unclipped_blend;
3669 rasterizer->setClipRect(clipRect);
3670 rasterizer->initialize(blend, data);
3673 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3674 ProcessSpans callback,
3675 QSpanData *spanData, QRasterBuffer *rasterBuffer)
3677 if (!callback || !outline)
3680 Q_Q(QRasterPaintEngine);
3681 QRasterPaintEngineState *s = q->state();
3683 if (!s->flags.antialiased) {
3684 initializeRasterizer(spanData);
3686 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3690 rasterizer->rasterize(outline, fillRule);
3694 rasterize(outline, callback, (void *)spanData, rasterBuffer);
3698 int q_gray_rendered_spans(QT_FT_Raster raster);
3701 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3702 ProcessSpans callback,
3703 void *userData, QRasterBuffer *)
3705 if (!callback || !outline)
3708 Q_Q(QRasterPaintEngine);
3709 QRasterPaintEngineState *s = q->state();
3711 if (!s->flags.antialiased) {
3712 rasterizer->setAntialiased(s->flags.antialiased);
3713 rasterizer->setClipRect(deviceRect);
3714 rasterizer->initialize(callback, userData);
3716 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3720 rasterizer->rasterize(outline, fillRule);
3724 // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3725 // minimize memory reallocations. However if initial size for
3726 // raster pool is changed for lower value, reallocations will
3728 const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3729 int rasterPoolSize = rasterPoolInitialSize;
3730 unsigned char *rasterPoolBase;
3731 #if defined(Q_WS_WIN64)
3733 // We make use of setjmp and longjmp in qgrayraster.c which requires
3734 // 16-byte alignment, hence we hardcode this requirement here..
3735 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3737 unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3738 rasterPoolBase = rasterPoolOnStack;
3740 Q_CHECK_PTR(rasterPoolBase);
3742 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3744 void *data = userData;
3746 QT_FT_BBox clip_box = { deviceRect.x(),
3748 deviceRect.x() + deviceRect.width(),
3749 deviceRect.y() + deviceRect.height() };
3751 QT_FT_Raster_Params rasterParams;
3752 rasterParams.target = 0;
3753 rasterParams.source = outline;
3754 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3755 rasterParams.gray_spans = 0;
3756 rasterParams.black_spans = 0;
3757 rasterParams.bit_test = 0;
3758 rasterParams.bit_set = 0;
3759 rasterParams.user = data;
3760 rasterParams.clip_box = clip_box;
3765 int rendered_spans = 0;
3769 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3770 rasterParams.gray_spans = callback;
3771 rasterParams.skip_spans = rendered_spans;
3772 error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3774 // Out of memory, reallocate some more and try again...
3775 if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3776 int new_size = rasterPoolSize * 2;
3777 if (new_size > 1024 * 1024) {
3778 qWarning("QPainter: Rasterization of primitive failed");
3782 rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3784 #if defined(Q_WS_WIN64)
3785 _aligned_free(rasterPoolBase);
3787 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3788 free(rasterPoolBase);
3791 rasterPoolSize = new_size;
3793 #if defined(Q_WS_WIN64)
3794 // We make use of setjmp and longjmp in qgrayraster.c which requires
3795 // 16-byte alignment, hence we hardcode this requirement here..
3796 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3798 (unsigned char *) malloc(rasterPoolSize);
3800 Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3802 qt_ft_grays_raster.raster_done(*grayRaster.data());
3803 qt_ft_grays_raster.raster_new(grayRaster.data());
3804 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3810 #if defined(Q_WS_WIN64)
3811 _aligned_free(rasterPoolBase);
3813 if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3814 free(rasterPoolBase);
3818 void QRasterPaintEnginePrivate::recalculateFastImages()
3820 Q_Q(QRasterPaintEngine);
3821 QRasterPaintEngineState *s = q->state();
3823 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3824 && s->matrix.type() <= QTransform::TxShear;
3827 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3829 Q_Q(const QRasterPaintEngine);
3830 const QRasterPaintEngineState *s = q->state();
3832 return s->flags.fast_images
3833 && (mode == QPainter::CompositionMode_SourceOver
3834 || (mode == QPainter::CompositionMode_Source
3835 && !image.hasAlphaChannel()));
3838 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3840 Q_ASSERT(image.depth() == 1);
3842 QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3843 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3845 QRgb fg = PREMUL(color.rgba());
3848 int height = sourceImage.height();
3849 int width = sourceImage.width();
3850 for (int y=0; y<height; ++y) {
3851 uchar *source = sourceImage.scanLine(y);
3852 QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3853 if (!source || !target)
3854 QT_THROW(std::bad_alloc()); // we must have run out of memory
3855 for (int x=0; x < width; ++x)
3856 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3861 QRasterBuffer::~QRasterBuffer()
3865 void QRasterBuffer::init()
3867 compositionMode = QPainter::CompositionMode_SourceOver;
3868 monoDestinationWithClut = false;
3873 QImage::Format QRasterBuffer::prepare(QImage *image)
3875 m_buffer = (uchar *)image->bits();
3876 m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3877 m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3878 bytes_per_pixel = image->depth()/8;
3879 bytes_per_line = image->bytesPerLine();
3881 format = image->format();
3882 drawHelper = qDrawHelper + format;
3883 if (image->depth() == 1 && image->colorTable().size() == 2) {
3884 monoDestinationWithClut = true;
3885 destColor0 = PREMUL(image->colorTable()[0]);
3886 destColor1 = PREMUL(image->colorTable()[1]);
3892 void QRasterBuffer::resetBuffer(int val)
3894 memset(m_buffer, val, m_height*bytes_per_line);
3898 #if defined(Q_WS_QWS)
3899 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3901 m_buffer = reinterpret_cast<uchar*>(device->memory());
3902 m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3903 m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3904 bytes_per_pixel = device->depth() / 8;
3905 bytes_per_line = device->bytesPerLine();
3906 format = device->format();
3907 #ifndef QT_NO_RASTERCALLBACKS
3909 drawHelper = qDrawHelperCallback + format;
3912 drawHelper = qDrawHelper + format;
3915 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3919 return widget->frameGeometry().width();
3921 return widget->frameGeometry().height();
3926 return qt_paint_device_metric(widget, m);
3929 int QCustomRasterPaintDevice::bytesPerLine() const
3931 return (width() * depth() + 7) / 8;
3934 #elif defined(Q_OS_SYMBIAN)
3936 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3940 #endif // Q_OS_SYMBIAN
3943 \class QCustomRasterPaintDevice
3948 \brief The QCustomRasterPaintDevice class is provided to activate
3949 hardware accelerated paint engines in Qt for Embedded Linux.
3951 Note that this class is only available in \l{Qt for Embedded Linux}.
3953 In \l{Qt for Embedded Linux}, painting is a pure software
3954 implementation. But starting with Qt 4.2, it is
3955 possible to add an accelerated graphics driver to take advantage
3956 of available hardware resources.
3958 Hardware acceleration is accomplished by creating a custom screen
3959 driver, accelerating the copying from memory to the screen, and
3960 implementing a custom paint engine accelerating the various
3961 painting operations. Then a custom paint device (derived from the
3962 QCustomRasterPaintDevice class) and a custom window surface
3963 (derived from QWSWindowSurface) must be implemented to make
3964 \l{Qt for Embedded Linux} aware of the accelerated driver.
3966 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
3967 documentation for details.
3969 \sa QRasterPaintEngine, QPaintDevice
3973 \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
3975 Constructs a custom raster based paint device for the given
3976 top-level \a widget.
3980 \fn int QCustomRasterPaintDevice::bytesPerLine() const
3982 Returns the number of bytes per line in the framebuffer. Note that
3983 this number might be larger than the framebuffer width.
3987 \fn int QCustomRasterPaintDevice::devType() const
3992 \fn QImage::Format QCustomRasterPaintDevice::format() const
3994 Returns the format of the device's memory buffet.
3996 The default format is QImage::Format_ARGB32_Premultiplied. The
3997 only other valid format is QImage::Format_RGB16.
4001 \fn void * QCustomRasterPaintDevice::memory () const
4003 Returns a pointer to the paint device's memory buffer, or 0 if no
4008 \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4013 \fn QSize QCustomRasterPaintDevice::size () const
4018 QClipData::QClipData(int height)
4020 clipSpanHeight = height;
4025 xmin = xmax = ymin = ymax = 0;
4029 hasRectClip = hasRegionClip = false;
4032 QClipData::~QClipData()
4040 void QClipData::initialize()
4046 m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4048 Q_CHECK_PTR(m_clipLines);
4050 m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4051 allocated = clipSpanHeight;
4052 Q_CHECK_PTR(m_spans);
4058 m_clipLines[y].spans = 0;
4059 m_clipLines[y].count = 0;
4063 const int len = clipRect.width();
4066 QSpan *span = m_spans + count;
4070 span->coverage = 255;
4073 m_clipLines[y].spans = span;
4074 m_clipLines[y].count = 1;
4078 while (y < clipSpanHeight) {
4079 m_clipLines[y].spans = 0;
4080 m_clipLines[y].count = 0;
4083 } else if (hasRegionClip) {
4085 const QVector<QRect> rects = clipRegion.rects();
4086 const int numRects = rects.size();
4089 const int maxSpans = (ymax - ymin) * numRects;
4090 if (maxSpans > allocated) {
4091 m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4092 allocated = maxSpans;
4097 int firstInBand = 0;
4099 while (firstInBand < numRects) {
4100 const int currMinY = rects.at(firstInBand).y();
4101 const int currMaxY = currMinY + rects.at(firstInBand).height();
4103 while (y < currMinY) {
4104 m_clipLines[y].spans = 0;
4105 m_clipLines[y].count = 0;
4109 int lastInBand = firstInBand;
4110 while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4113 while (y < currMaxY) {
4115 m_clipLines[y].spans = m_spans + count;
4116 m_clipLines[y].count = lastInBand - firstInBand + 1;
4118 for (int r = firstInBand; r <= lastInBand; ++r) {
4119 const QRect &currRect = rects.at(r);
4120 QSpan *span = m_spans + count;
4121 span->x = currRect.x();
4122 span->len = currRect.width();
4124 span->coverage = 255;
4130 firstInBand = lastInBand + 1;
4133 Q_ASSERT(count <= allocated);
4135 while (y < clipSpanHeight) {
4136 m_clipLines[y].spans = 0;
4137 m_clipLines[y].count = 0;
4143 free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4148 free(m_clipLines); // same for clipLines
4154 void QClipData::fixup()
4159 ymin = ymax = xmin = xmax = 0;
4164 ymin = m_spans[0].y;
4165 ymax = m_spans[count-1].y + 1;
4169 const int firstLeft = m_spans[0].x;
4170 const int firstRight = m_spans[0].x + m_spans[0].len;
4173 for (int i = 0; i < count; ++i) {
4174 QT_FT_Span_& span = m_spans[i];
4177 if (span.y != y + 1 && y != -1)
4180 m_clipLines[y].spans = &span;
4181 m_clipLines[y].count = 1;
4183 ++m_clipLines[y].count;
4185 const int spanLeft = span.x;
4186 const int spanRight = spanLeft + span.len;
4188 if (spanLeft < xmin)
4191 if (spanRight > xmax)
4194 if (spanLeft != firstLeft || spanRight != firstRight)
4200 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4205 Convert \a rect to clip spans.
4207 void QClipData::setClipRect(const QRect &rect)
4209 if (hasRectClip && rect == clipRect)
4212 // qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4214 hasRegionClip = false;
4218 xmax = rect.x() + rect.width();
4219 ymin = qMin(rect.y(), clipSpanHeight);
4220 ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4227 // qDebug() << xmin << xmax << ymin << ymax;
4231 Convert \a region to clip spans.
4233 void QClipData::setClipRegion(const QRegion ®ion)
4235 if (region.rectCount() == 1) {
4236 setClipRect(region.rects().at(0));
4240 hasRegionClip = true;
4241 hasRectClip = false;
4242 clipRegion = region;
4244 { // set bounding rect
4245 const QRect rect = region.boundingRect();
4247 xmax = rect.x() + rect.width();
4249 ymax = rect.y() + rect.height();
4261 spans must be sorted on y
4263 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4264 const QSpan *spans, const QSpan *end,
4265 QSpan **outSpans, int available)
4267 const_cast<QClipData *>(clip)->initialize();
4269 QSpan *out = *outSpans;
4271 const QSpan *clipSpans = clip->m_spans + *currentClip;
4272 const QSpan *clipEnd = clip->m_spans + clip->count;
4274 while (available && spans < end ) {
4275 if (clipSpans >= clipEnd) {
4279 if (clipSpans->y > spans->y) {
4283 if (spans->y != clipSpans->y) {
4284 if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4285 clipSpans = clip->m_clipLines[spans->y].spans;
4290 Q_ASSERT(spans->y == clipSpans->y);
4293 int sx2 = sx1 + spans->len;
4294 int cx1 = clipSpans->x;
4295 int cx2 = cx1 + clipSpans->len;
4297 if (cx1 < sx1 && cx2 < sx1) {
4300 } else if (sx1 < cx1 && sx2 < cx1) {
4304 int x = qMax(sx1, cx1);
4305 int len = qMin(sx2, cx2) - x;
4307 out->x = qMax(sx1, cx1);
4308 out->len = qMin(sx2, cx2) - out->x;
4310 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4322 *currentClip = clipSpans - clip->m_spans;
4326 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4328 // qDebug() << "qt_span_fill_clipped" << spanCount;
4329 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4331 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4333 const int NSPANS = 256;
4334 QSpan cspans[NSPANS];
4335 int currentClip = 0;
4336 const QSpan *end = spans + spanCount;
4337 while (spans < end) {
4338 QSpan *clipped = cspans;
4339 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4340 // qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4341 // << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4343 if (clipped - cspans)
4344 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4350 Clip spans to \a{clip}-rectangle.
4351 Returns number of unclipped spans
4353 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4356 const short minx = clip.left();
4357 const short miny = clip.top();
4358 const short maxx = clip.right();
4359 const short maxy = clip.bottom();
4362 for (int i = 0; i < numSpans; ++i) {
4363 if (spans[i].y > maxy)
4365 if (spans[i].y < miny
4366 || spans[i].x > maxx
4367 || spans[i].x + spans[i].len <= minx) {
4370 if (spans[i].x < minx) {
4371 spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4374 spans[n].x = spans[i].x;
4375 spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4377 if (spans[n].len == 0)
4379 spans[n].y = spans[i].y;
4380 spans[n].coverage = spans[i].coverage;
4387 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4390 QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4391 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4393 Q_ASSERT(fillData->clip);
4394 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4396 // hw: check if this const_cast<> is safe!!!
4397 count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4398 fillData->clip->clipRect);
4400 fillData->unclipped_blend(count, spans, fillData);
4403 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4405 ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4407 // qDebug() << " qt_span_clip: " << count << clipData->operation;
4408 // for (int i = 0; i < qMin(count, 10); ++i) {
4409 // qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4412 switch (clipData->operation) {
4414 case Qt::IntersectClip:
4416 QClipData *newClip = clipData->newClip;
4417 newClip->initialize();
4419 int currentClip = 0;
4420 const QSpan *end = spans + count;
4421 while (spans < end) {
4422 QSpan *newspans = newClip->m_spans + newClip->count;
4423 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4424 &newspans, newClip->allocated - newClip->count);
4425 newClip->count = newspans - newClip->m_spans;
4427 newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4428 newClip->allocated *= 2;
4435 case Qt::ReplaceClip:
4436 clipData->newClip->appendSpans(spans, count);
4444 QImage QRasterBuffer::bufferImage() const
4446 QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4448 for (int y = 0; y < m_height; ++y) {
4449 uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4451 for (int x=0; x<m_width; ++x) {
4452 uint argb = span[x];
4453 image.setPixel(x, y, argb);
4461 void QRasterBuffer::flushToARGBImage(QImage *target) const
4463 int w = qMin(m_width, target->width());
4464 int h = qMin(m_height, target->height());
4466 for (int y=0; y<h; ++y) {
4467 uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4468 QRgb *dest = (QRgb *) target->scanLine(y);
4469 for (int x=0; x<w; ++x) {
4470 QRgb pixel = sourceLine[x];
4471 int alpha = qAlpha(pixel);
4475 dest[x] = (alpha << 24)
4476 | ((255*qRed(pixel)/alpha) << 16)
4477 | ((255*qGreen(pixel)/alpha) << 8)
4478 | ((255*qBlue(pixel)/alpha) << 0);
4485 class QGradientCache
4489 inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4490 stops(s), opacity(op), interpolationMode(mode) {}
4491 uint buffer[GRADIENT_STOPTABLE_SIZE];
4492 QGradientStops stops;
4494 QGradient::InterpolationMode interpolationMode;
4497 typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4500 inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4501 quint64 hash_val = 0;
4503 QGradientStops stops = gradient.stops();
4504 for (int i = 0; i < stops.size() && i <= 2; i++)
4505 hash_val += stops[i].second.rgba();
4507 QMutexLocker lock(&mutex);
4508 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4510 if (it == cache.constEnd())
4511 return addCacheElement(hash_val, gradient, opacity);
4514 const CacheInfo &cache_info = it.value();
4515 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4516 return cache_info.buffer;
4518 } while (it != cache.constEnd() && it.key() == hash_val);
4519 // an exact match for these stops and opacity was not found, create new cache
4520 return addCacheElement(hash_val, gradient, opacity);
4524 inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4526 inline int maxCacheSize() const { return 60; }
4527 inline void generateGradientColorTable(const QGradient& g,
4529 int size, int opacity) const;
4530 uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4531 if (cache.size() == maxCacheSize()) {
4532 // may remove more than 1, but OK
4533 cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4535 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4536 generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4537 return cache.insert(hash_val, cache_entry).value().buffer;
4540 QGradientColorTableHash cache;
4544 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4546 QGradientStops stops = gradient.stops();
4547 int stopCount = stops.count();
4548 Q_ASSERT(stopCount > 0);
4550 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4552 if (stopCount == 2) {
4553 uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4554 uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4556 qreal first_stop = stops[0].first;
4557 qreal second_stop = stops[1].first;
4559 if (second_stop < first_stop) {
4560 qSwap(first_color, second_color);
4561 qSwap(first_stop, second_stop);
4564 if (colorInterpolation) {
4565 first_color = PREMUL(first_color);
4566 second_color = PREMUL(second_color);
4569 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4570 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4572 uint red_first = qRed(first_color) << 16;
4573 uint green_first = qGreen(first_color) << 16;
4574 uint blue_first = qBlue(first_color) << 16;
4575 uint alpha_first = qAlpha(first_color) << 16;
4577 uint red_second = qRed(second_color) << 16;
4578 uint green_second = qGreen(second_color) << 16;
4579 uint blue_second = qBlue(second_color) << 16;
4580 uint alpha_second = qAlpha(second_color) << 16;
4583 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4584 if (colorInterpolation)
4585 colorTable[i] = first_color;
4587 colorTable[i] = PREMUL(first_color);
4590 if (i < second_index) {
4591 qreal reciprocal = qreal(1) / (second_index - first_index);
4593 int red_delta = qRound(int(red_second - red_first) * reciprocal);
4594 int green_delta = qRound(int(green_second - green_first) * reciprocal);
4595 int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4596 int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4599 red_first += 1 << 15;
4600 green_first += 1 << 15;
4601 blue_first += 1 << 15;
4602 alpha_first += 1 << 15;
4604 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4605 red_first += red_delta;
4606 green_first += green_delta;
4607 blue_first += blue_delta;
4608 alpha_first += alpha_delta;
4610 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4611 | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4613 if (colorInterpolation)
4614 colorTable[i] = color;
4616 colorTable[i] = PREMUL(color);
4620 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4621 if (colorInterpolation)
4622 colorTable[i] = second_color;
4624 colorTable[i] = PREMUL(second_color);
4630 uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4631 if (stopCount == 1) {
4632 current_color = PREMUL(current_color);
4633 for (int i = 0; i < size; ++i)
4634 colorTable[i] = current_color;
4638 // The position where the gradient begins and ends
4639 qreal begin_pos = stops[0].first;
4640 qreal end_pos = stops[stopCount-1].first;
4642 int pos = 0; // The position in the color table.
4645 qreal incr = 1 / qreal(size); // the double increment.
4646 qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4648 // Up to first point
4649 colorTable[pos++] = PREMUL(current_color);
4650 while (dpos <= begin_pos) {
4651 colorTable[pos] = colorTable[pos - 1];
4656 int current_stop = 0; // We always interpolate between current and current + 1.
4658 qreal t; // position between current left and right stops
4659 qreal t_delta; // the t increment per entry in the color table
4661 if (dpos < end_pos) {
4663 while (dpos > stops[current_stop+1].first)
4666 if (current_stop != 0)
4667 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4668 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4670 if (colorInterpolation) {
4671 current_color = PREMUL(current_color);
4672 next_color = PREMUL(next_color);
4675 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4676 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4677 t = (dpos - stops[current_stop].first) * c;
4681 Q_ASSERT(current_stop < stopCount);
4683 int dist = qRound(t);
4684 int idist = 256 - dist;
4686 if (colorInterpolation)
4687 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4689 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4694 if (dpos >= end_pos)
4700 while (dpos > stops[current_stop+skip+1].first)
4704 current_stop += skip;
4706 current_color = next_color;
4708 current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4709 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4711 if (colorInterpolation) {
4713 current_color = PREMUL(current_color);
4714 next_color = PREMUL(next_color);
4717 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4718 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4719 t = (dpos - stops[current_stop].first) * c;
4726 current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4727 while (pos < size - 1) {
4728 colorTable[pos] = current_color;
4732 // Make sure the last color stop is represented at the end of the table
4733 colorTable[size - 1] = current_color;
4736 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4739 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4743 rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4748 m11 = m22 = m33 = 1.;
4749 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4750 clip = pe ? pe->d_func()->clip() : 0;
4753 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4755 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4757 Qt::BrushStyle brushStyle = qbrush_style(brush);
4758 switch (brushStyle) {
4759 case Qt::SolidPattern: {
4761 QColor c = qbrush_color(brush);
4762 QRgb rgba = c.rgba();
4763 solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4764 if ((solid.color & 0xff000000) == 0
4765 && compositionMode == QPainter::CompositionMode_SourceOver) {
4771 case Qt::LinearGradientPattern:
4773 type = LinearGradient;
4774 const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4775 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4776 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4777 gradient.spread = g->spread();
4779 QLinearGradientData &linearData = gradient.linear;
4781 linearData.origin.x = g->start().x();
4782 linearData.origin.y = g->start().y();
4783 linearData.end.x = g->finalStop().x();
4784 linearData.end.y = g->finalStop().y();
4788 case Qt::RadialGradientPattern:
4790 type = RadialGradient;
4791 const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4792 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4793 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4794 gradient.spread = g->spread();
4796 QRadialGradientData &radialData = gradient.radial;
4798 QPointF center = g->center();
4799 radialData.center.x = center.x();
4800 radialData.center.y = center.y();
4801 radialData.center.radius = g->centerRadius();
4802 QPointF focal = g->focalPoint();
4803 radialData.focal.x = focal.x();
4804 radialData.focal.y = focal.y();
4805 radialData.focal.radius = g->focalRadius();
4809 case Qt::ConicalGradientPattern:
4811 type = ConicalGradient;
4812 const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4813 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4814 gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4815 gradient.spread = QGradient::RepeatSpread;
4817 QConicalGradientData &conicalData = gradient.conical;
4819 QPointF center = g->center();
4820 conicalData.center.x = center.x();
4821 conicalData.center.y = center.y();
4822 conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4826 case Qt::Dense1Pattern:
4827 case Qt::Dense2Pattern:
4828 case Qt::Dense3Pattern:
4829 case Qt::Dense4Pattern:
4830 case Qt::Dense5Pattern:
4831 case Qt::Dense6Pattern:
4832 case Qt::Dense7Pattern:
4833 case Qt::HorPattern:
4834 case Qt::VerPattern:
4835 case Qt::CrossPattern:
4836 case Qt::BDiagPattern:
4837 case Qt::FDiagPattern:
4838 case Qt::DiagCrossPattern:
4841 tempImage = new QImage();
4842 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4843 initTexture(tempImage, alpha, QTextureData::Tiled);
4845 case Qt::TexturePattern:
4848 tempImage = new QImage();
4850 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4851 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4853 *tempImage = brush.textureImage();
4854 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4862 adjustSpanMethods();
4865 void QSpanData::adjustSpanMethods()
4875 unclipped_blend = 0;
4878 unclipped_blend = rasterBuffer->drawHelper->blendColor;
4879 bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4880 alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4881 alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4882 fillRect = rasterBuffer->drawHelper->fillRect;
4884 case LinearGradient:
4885 case RadialGradient:
4886 case ConicalGradient:
4887 unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4891 #ifndef QT_NO_RASTERCALLBACKS
4892 if (!rasterBuffer->buffer())
4893 unclipped_blend = qBlendTextureCallback;
4896 unclipped_blend = qBlendTexture;
4898 unclipped_blend = qBlendTexture;
4900 if (!texture.imageData)
4901 unclipped_blend = 0;
4906 if (!unclipped_blend) {
4909 blend = unclipped_blend;
4910 } else if (clip->hasRectClip) {
4911 blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4913 blend = qt_span_fill_clipped;
4917 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4920 // make sure we round off correctly in qdrawhelper.cpp
4921 delta.translate(1.0 / 65536, 1.0 / 65536);
4923 QTransform inv = (delta * matrix).inverted();
4936 const bool affine = !m13 && !m23;
4937 fast_matrix = affine
4938 && m11 * m11 + m21 * m21 < 1e4
4939 && m12 * m12 + m22 * m22 < 1e4
4943 adjustSpanMethods();
4946 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4948 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4950 const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4951 if (!d || d->height == 0) {
4952 texture.imageData = 0;
4959 texture.bytesPerLine = 0;
4960 texture.format = QImage::Format_Invalid;
4961 texture.colorTable = 0;
4962 texture.hasAlpha = alpha != 256;
4964 texture.imageData = d->data;
4965 texture.width = d->width;
4966 texture.height = d->height;
4968 if (sourceRect.isNull()) {
4971 texture.x2 = texture.width;
4972 texture.y2 = texture.height;
4974 texture.x1 = sourceRect.x();
4975 texture.y1 = sourceRect.y();
4976 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4977 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4980 texture.bytesPerLine = d->bytes_per_line;
4982 texture.format = d->format;
4983 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4984 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4986 texture.const_alpha = alpha;
4987 texture.type = _type;
4989 adjustSpanMethods();
4994 \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4997 Draws the first \a pointCount points in the buffer \a points
4999 The default implementation converts the first \a pointCount QPoints in \a points
5000 to QPointFs and calls the floating point version of drawPoints.
5004 \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5007 Reimplement this function to draw the largest ellipse that can be
5008 contained within rectangle \a rect.
5011 #ifdef QT_DEBUG_DRAW
5012 void dumpClip(int width, int height, const QClipData *clip)
5014 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5015 clipImg.fill(0xffff0000);
5022 ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5024 for (int i = 0; i < clip->count; ++i) {
5025 const QSpan *span = ((QClipData *) clip)->spans() + i;
5026 for (int j = 0; j < span->len; ++j)
5027 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5028 x0 = qMin(x0, int(span->x));
5029 x1 = qMax(x1, int(span->x + span->len - 1));
5031 y0 = qMin(y0, int(span->y));
5032 y1 = qMax(y1, int(span->y));
5035 static int counter = 0;
5042 fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5043 clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));