source: trunk/src/gui/painting/qpaintengine_raster.cpp@ 758

Last change on this file since 758 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 193.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtCore/qglobal.h>
43
44#define QT_FT_BEGIN_HEADER
45#define QT_FT_END_HEADER
46
47#include <private/qrasterdefs_p.h>
48#include <private/qgrayraster_p.h>
49
50#include <qpainterpath.h>
51#include <qdebug.h>
52#include <qhash.h>
53#include <qlabel.h>
54#include <qbitmap.h>
55#include <qmath.h>
56
57#if defined (Q_WS_X11) || (defined(Q_WS_PM) && !defined(QT_NO_FREETYPE))
58# include <private/qfontengine_ft_p.h>
59#endif
60
61// #include <private/qdatabuffer_p.h>
62// #include <private/qpainter_p.h>
63#include <private/qmath_p.h>
64#include <private/qtextengine_p.h>
65#include <private/qfontengine_p.h>
66#include <private/qpixmap_raster_p.h>
67// #include <private/qpolygonclipper_p.h>
68// #include <private/qrasterizer_p.h>
69#include <private/qimage_p.h>
70
71#include "qpaintengine_raster_p.h"
72// #include "qbezier_p.h"
73#include "qoutlinemapper_p.h"
74
75#if defined(Q_WS_WIN)
76# include <qt_windows.h>
77# include <qvarlengtharray.h>
78# include <private/qfontengine_p.h>
79# if defined(Q_OS_WINCE)
80# include "qguifunctions_wince.h"
81# endif
82#elif defined(Q_WS_MAC)
83# include <private/qt_mac_p.h>
84# include <private/qpixmap_mac_p.h>
85# include <private/qpaintengine_mac_p.h>
86#elif defined(Q_WS_QWS)
87# if !defined(QT_NO_FREETYPE)
88# include <private/qfontengine_ft_p.h>
89# endif
90# if !defined(QT_NO_QWS_QPF2)
91# include <private/qfontengine_qpf_p.h>
92# endif
93# include <private/qabstractfontengine_p.h>
94#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
95# include <private/qfontengine_s60_p.h>
96#endif
97
98#if defined(Q_WS_WIN64)
99# include <malloc.h>
100#endif
101#include <limits.h>
102
103#if defined(QT_NO_FPU) || (_MSC_VER >= 1300 && _MSC_VER < 1400)
104# define FLOATING_POINT_BUGGY_OR_NO_FPU
105#endif
106
107QT_BEGIN_NAMESPACE
108
109extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
110
111#define qreal_to_fixed_26_6(f) (int(f * 64))
112#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
113#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
114
115// #define QT_DEBUG_DRAW
116#ifdef QT_DEBUG_DRAW
117void dumpClip(int width, int height, const QClipData *clip);
118#endif
119
120#define QT_FAST_SPANS
121
122
123// A little helper macro to get a better approximation of dimensions.
124// If we have a rect that starting at 0.5 of width 3.5 it should span
125// 4 pixels.
126#define int_dim(pos, dim) (int(pos+dim) - int(pos))
127
128// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
129static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
130
131#ifdef Q_WS_WIN
132extern bool qt_cleartype_enabled;
133#endif
134
135#ifdef Q_WS_MAC
136extern bool qt_applefontsmoothing_enabled;
137#endif
138
139
140/********************************************************************************
141 * Span functions
142 */
143static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
144static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
145static void qt_span_clip(int count, const QSpan *spans, void *userData);
146static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
147
148struct ClipData
149{
150 QClipData *oldClip;
151 QClipData *newClip;
152 Qt::ClipOperation operation;
153};
154
155enum LineDrawMode {
156 LineDrawClipped,
157 LineDrawNormal,
158 LineDrawIncludeLastPixel
159};
160
161static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
162 LineDrawMode style, const QIntRect &rect);
163static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
164 QPen *pen, ProcessSpans span_func, QSpanData *data,
165 LineDrawMode style, const QIntRect &devRect,
166 int *patternOffset);
167// static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2,
168// ProcessSpans span_func, QSpanData *data,
169// LineDrawMode style, const QRect &devRect);
170
171static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
172 ProcessSpans pen_func, ProcessSpans brush_func,
173 QSpanData *pen_data, QSpanData *brush_data);
174
175struct QRasterFloatPoint {
176 qreal x;
177 qreal y;
178};
179
180#ifdef QT_DEBUG_DRAW
181static const QRectF boundingRect(const QPointF *points, int pointCount)
182{
183 const QPointF *e = points;
184 const QPointF *last = points + pointCount;
185 qreal minx, maxx, miny, maxy;
186 minx = maxx = e->x();
187 miny = maxy = e->y();
188 while (++e < last) {
189 if (e->x() < minx)
190 minx = e->x();
191 else if (e->x() > maxx)
192 maxx = e->x();
193 if (e->y() < miny)
194 miny = e->y();
195 else if (e->y() > maxy)
196 maxy = e->y();
197 }
198 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
199}
200#endif
201
202template <typename T> static inline bool isRect(const T *pts, int elementCount) {
203 return (elementCount == 5 // 5-point polygon, check for closed rect
204 && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
205 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
206 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
207 && pts[0] < pts[4] && pts[1] < pts[5]
208 ) ||
209 (elementCount == 4 // 4-point polygon, check for unclosed rect
210 && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
211 && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
212 && pts[0] < pts[4] && pts[1] < pts[5]
213 );
214}
215
216
217static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
218{
219 ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
220}
221
222static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
223{
224 ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
225}
226
227static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
228 qfixed c2x, qfixed c2y,
229 qfixed ex, qfixed ey,
230 void *data)
231{
232 ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
233 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
234 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
235}
236
237
238#if !defined(QT_NO_DEBUG) && 0
239static void qt_debug_path(const QPainterPath &path)
240{
241 const char *names[] = {
242 "MoveTo ",
243 "LineTo ",
244 "CurveTo ",
245 "CurveToData"
246 };
247
248 fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
249 for (int i=0; i<path.elementCount(); ++i) {
250 const QPainterPath::Element &e = path.elementAt(i);
251 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
252 fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
253 }
254}
255#endif
256
257
258
259/*!
260 \class QRasterPaintEngine
261 \preliminary
262 \ingroup qws
263 \since 4.2
264
265 \brief The QRasterPaintEngine class enables hardware acceleration
266 of painting operations in Qt for Embedded Linux.
267
268 Note that this functionality is only available in
269 \l{Qt for Embedded Linux}.
270
271 In \l{Qt for Embedded Linux}, painting is a pure software
272 implementation. But starting with Qt 4.2, it is
273 possible to add an accelerated graphics driver to take advantage
274 of available hardware resources.
275
276 Hardware acceleration is accomplished by creating a custom screen
277 driver, accelerating the copying from memory to the screen, and
278 implementing a custom paint engine accelerating the various
279 painting operations. Then a custom paint device (derived from the
280 QCustomRasterPaintDevice class) and a custom window surface
281 (derived from QWSWindowSurface) must be implemented to make
282 \l{Qt for Embedded Linux} aware of the accelerated driver.
283
284 \note The QRasterPaintEngine class does not support 8-bit images.
285 Instead, they need to be converted to a supported format, such as
286 QImage::Format_ARGB32_Premultiplied.
287
288 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
289 documentation for details.
290
291 \sa QCustomRasterPaintDevice, QPaintEngine
292*/
293
294/*!
295 \fn Type QRasterPaintEngine::type() const
296 \reimp
297*/
298
299/*!
300 \typedef QSpan
301 \relates QRasterPaintEngine
302
303 A struct equivalent to QT_FT_Span, containing a position (x,
304 y), the span's length in pixels and its color/coverage (a value
305 ranging from 0 to 255).
306*/
307
308/*!
309 \since 4.5
310
311 Creates a raster based paint engine for operating on the given
312 \a device, with the complete set of \l
313 {QPaintEngine::PaintEngineFeature}{paint engine features and
314 capabilities}.
315*/
316QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
317 : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
318{
319 d_func()->device = device;
320 init();
321}
322
323/*!
324 \internal
325*/
326QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
327 : QPaintEngineEx(dd)
328{
329 d_func()->device = device;
330 init();
331}
332
333void QRasterPaintEngine::init()
334{
335 Q_D(QRasterPaintEngine);
336
337
338#ifdef Q_WS_WIN
339 d->hdc = 0;
340#endif
341
342 d->rasterPoolSize = 8192;
343 d->rasterPoolBase =
344#if defined(Q_WS_WIN64)
345 // We make use of setjmp and longjmp in qgrayraster.c which requires
346 // 16-byte alignment, hence we hardcode this requirement here..
347 (unsigned char *) _aligned_malloc(d->rasterPoolSize, sizeof(void*) * 2);
348#else
349 (unsigned char *) malloc(d->rasterPoolSize);
350#endif
351 Q_CHECK_PTR(d->rasterPoolBase);
352
353 // The antialiasing raster.
354 d->grayRaster.reset(new QT_FT_Raster);
355 Q_CHECK_PTR(d->grayRaster.data());
356 if (qt_ft_grays_raster.raster_new(0, d->grayRaster.data()))
357 QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
358
359
360 qt_ft_grays_raster.raster_reset(*d->grayRaster.data(), d->rasterPoolBase, d->rasterPoolSize);
361
362 d->rasterizer.reset(new QRasterizer);
363 d->rasterBuffer.reset(new QRasterBuffer());
364 d->outlineMapper.reset(new QOutlineMapper);
365 d->outlinemapper_xform_dirty = true;
366
367 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
368 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
369 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
370
371 d->baseClip.reset(new QClipData(d->device->height()));
372 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
373
374 d->image_filler.init(d->rasterBuffer.data(), this);
375 d->image_filler.type = QSpanData::Texture;
376
377 d->image_filler_xform.init(d->rasterBuffer.data(), this);
378 d->image_filler_xform.type = QSpanData::Texture;
379
380 d->solid_color_filler.init(d->rasterBuffer.data(), this);
381 d->solid_color_filler.type = QSpanData::Solid;
382
383 d->deviceDepth = d->device->depth();
384
385 d->mono_surface = false;
386 gccaps &= ~PorterDuff;
387
388 QImage::Format format = QImage::Format_Invalid;
389
390 switch (d->device->devType()) {
391 case QInternal::Pixmap:
392 qWarning("QRasterPaintEngine: unsupported for pixmaps...");
393 break;
394 case QInternal::Image:
395 format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
396 break;
397#ifdef Q_WS_QWS
398 case QInternal::CustomRaster:
399 d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
400 break;
401#endif
402 default:
403 qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
404 d->device = 0;
405 return;
406 }
407
408 switch (format) {
409 case QImage::Format_MonoLSB:
410 case QImage::Format_Mono:
411 d->mono_surface = true;
412 break;
413 case QImage::Format_ARGB8565_Premultiplied:
414 case QImage::Format_ARGB8555_Premultiplied:
415 case QImage::Format_ARGB6666_Premultiplied:
416 case QImage::Format_ARGB4444_Premultiplied:
417 case QImage::Format_ARGB32_Premultiplied:
418 case QImage::Format_ARGB32:
419 gccaps |= PorterDuff;
420 break;
421 case QImage::Format_RGB32:
422 case QImage::Format_RGB444:
423 case QImage::Format_RGB555:
424 case QImage::Format_RGB666:
425 case QImage::Format_RGB888:
426 case QImage::Format_RGB16:
427 break;
428 default:
429 break;
430 }
431}
432
433
434
435
436/*!
437 Destroys this paint engine.
438*/
439QRasterPaintEngine::~QRasterPaintEngine()
440{
441 Q_D(QRasterPaintEngine);
442
443#if defined(Q_WS_WIN64)
444 _aligned_free(d->rasterPoolBase);
445#else
446 free(d->rasterPoolBase);
447#endif
448
449 qt_ft_grays_raster.raster_done(*d->grayRaster.data());
450}
451
452/*!
453 \reimp
454*/
455bool QRasterPaintEngine::begin(QPaintDevice *device)
456{
457 Q_D(QRasterPaintEngine);
458
459 if (device->devType() == QInternal::Pixmap) {
460 QPixmap *pixmap = static_cast<QPixmap *>(device);
461 if (pixmap->data->classId() == QPixmapData::RasterClass)
462 d->device = pixmap->data->buffer();
463 } else {
464 d->device = device;
465 }
466
467 // Make sure QPaintEngine::paintDevice() returns the proper device.
468 d->pdev = d->device;
469
470 Q_ASSERT(d->device->devType() == QInternal::Image
471 || d->device->devType() == QInternal::CustomRaster);
472
473 d->systemStateChanged();
474
475 QRasterPaintEngineState *s = state();
476 ensureOutlineMapper();
477 d->outlineMapper->m_clip_rect = d->deviceRect.adjusted(-10, -10, 10, 10);
478
479 // This is the upp
480 QRect bounds(-QT_RASTER_COORD_LIMIT, -QT_RASTER_COORD_LIMIT,
481 QT_RASTER_COORD_LIMIT*2 - 1, QT_RASTER_COORD_LIMIT * 2 - 1);
482 d->outlineMapper->m_clip_rect = bounds.intersected(d->outlineMapper->m_clip_rect);
483
484
485 d->rasterizer->setClipRect(d->deviceRect);
486
487 s->penData.init(d->rasterBuffer.data(), this);
488 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
489 s->stroker = &d->basicStroker;
490 d->basicStroker.setClipRect(d->deviceRect);
491
492 s->brushData.init(d->rasterBuffer.data(), this);
493 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
494
495 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
496
497 setDirty(DirtyBrushOrigin);
498
499#ifdef QT_DEBUG_DRAW
500 qDebug() << "QRasterPaintEngine::begin(" << (void *) device
501 << ") devType:" << device->devType()
502 << "devRect:" << d->deviceRect;
503 if (d->baseClip) {
504 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
505 }
506#endif
507
508#if defined(Q_WS_WIN)
509 d->isPlain45DegreeRotation = true;
510#endif
511
512 if (d->mono_surface)
513 d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
514#if defined(Q_WS_WIN)
515 else if (qt_cleartype_enabled)
516#elif defined (Q_WS_MAC)
517 else if (qt_applefontsmoothing_enabled)
518#else
519 else if (false)
520#endif
521 {
522 QImage::Format format = static_cast<QImage *>(d->device)->format();
523 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
524 d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
525 else
526 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
527 } else
528 d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
529
530 setActive(true);
531 return true;
532}
533
534/*!
535 \reimp
536*/
537bool QRasterPaintEngine::end()
538{
539#ifdef QT_DEBUG_DRAW
540 Q_D(QRasterPaintEngine);
541 qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
542 if (d->baseClip) {
543 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
544 }
545#endif
546
547 return true;
548}
549
550/*!
551 \internal
552*/
553void QRasterPaintEngine::releaseBuffer()
554{
555 Q_D(QRasterPaintEngine);
556 d->rasterBuffer.reset(new QRasterBuffer);
557}
558
559/*!
560 \internal
561*/
562QSize QRasterPaintEngine::size() const
563{
564 Q_D(const QRasterPaintEngine);
565 return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
566}
567
568/*!
569 \internal
570*/
571#ifndef QT_NO_DEBUG
572void QRasterPaintEngine::saveBuffer(const QString &s) const
573{
574 Q_D(const QRasterPaintEngine);
575 d->rasterBuffer->bufferImage().save(s, "PNG");
576}
577#endif
578
579/*!
580 \internal
581*/
582void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
583{
584 QRasterPaintEngineState *s = state();
585 // FALCON: get rid of this line, see drawImage call below.
586 s->matrix = matrix;
587 QTransform::TransformationType txop = s->matrix.type();
588
589 switch (txop) {
590
591 case QTransform::TxNone:
592 s->flags.int_xform = true;
593 break;
594
595 case QTransform::TxTranslate:
596 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
597 && qreal(int(s->matrix.dy())) == s->matrix.dy();
598 break;
599
600 case QTransform::TxScale:
601 s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
602 && qreal(int(s->matrix.dy())) == s->matrix.dy()
603 && qreal(int(s->matrix.m11())) == s->matrix.m11()
604 && qreal(int(s->matrix.m22())) == s->matrix.m22();
605 break;
606
607 default: // shear / perspective...
608 s->flags.int_xform = false;
609 break;
610 }
611
612 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
613
614 ensureOutlineMapper();
615
616#ifdef Q_WS_WIN
617 Q_D(QRasterPaintEngine);
618 d->isPlain45DegreeRotation = false;
619 if (txop >= QTransform::TxRotate) {
620 d->isPlain45DegreeRotation =
621 (qFuzzyIsNull(matrix.m11())
622 && qFuzzyIsNull(matrix.m12() - qreal(1))
623 && qFuzzyIsNull(matrix.m21() + qreal(1))
624 && qFuzzyIsNull(matrix.m22())
625 )
626 ||
627 (qFuzzyIsNull(matrix.m11() + qreal(1))
628 && qFuzzyIsNull(matrix.m12())
629 && qFuzzyIsNull(matrix.m21())
630 && qFuzzyIsNull(matrix.m22() + qreal(1))
631 )
632 ||
633 (qFuzzyIsNull(matrix.m11())
634 && qFuzzyIsNull(matrix.m12() + qreal(1))
635 && qFuzzyIsNull(matrix.m21() - qreal(1))
636 && qFuzzyIsNull(matrix.m22())
637 )
638 ;
639 }
640#endif
641
642}
643
644
645
646QRasterPaintEngineState::~QRasterPaintEngineState()
647{
648 if (flags.has_clip_ownership)
649 delete clip;
650}
651
652
653QRasterPaintEngineState::QRasterPaintEngineState()
654{
655 stroker = 0;
656
657 fillFlags = 0;
658 strokeFlags = 0;
659 pixmapFlags = 0;
660
661 intOpacity = 256;
662
663 txscale = 1.;
664
665 flags.fast_pen = true;
666 flags.antialiased = false;
667 flags.bilinear = false;
668 flags.fast_text = true;
669 flags.int_xform = true;
670 flags.tx_noshear = true;
671 flags.fast_images = true;
672
673 clip = 0;
674 flags.has_clip_ownership = false;
675
676 dirty = 0;
677}
678
679QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
680 : QPainterState(s)
681{
682 stroker = s.stroker;
683
684 lastBrush = s.lastBrush;
685 brushData = s.brushData;
686 brushData.tempImage = 0;
687
688 lastPen = s.lastPen;
689 penData = s.penData;
690 penData.tempImage = 0;
691
692 fillFlags = s.fillFlags;
693 strokeFlags = s.strokeFlags;
694 pixmapFlags = s.pixmapFlags;
695
696 intOpacity = s.intOpacity;
697
698 txscale = s.txscale;
699
700 flag_bits = s.flag_bits;
701
702 clip = s.clip;
703 flags.has_clip_ownership = false;
704
705 dirty = s.dirty;
706}
707
708/*!
709 \internal
710*/
711QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
712{
713 QRasterPaintEngineState *s;
714 if (!orig)
715 s = new QRasterPaintEngineState();
716 else
717 s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
718
719 return s;
720}
721
722/*!
723 \internal
724*/
725void QRasterPaintEngine::setState(QPainterState *s)
726{
727 Q_D(QRasterPaintEngine);
728 QPaintEngineEx::setState(s);
729 d->rasterBuffer->compositionMode = s->composition_mode;
730}
731
732/*!
733 \fn QRasterPaintEngineState *QRasterPaintEngine::state()
734 \internal
735*/
736
737/*!
738 \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
739 \internal
740*/
741
742/*!
743 \internal
744*/
745void QRasterPaintEngine::penChanged()
746{
747#ifdef QT_DEBUG_DRAW
748 qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
749#endif
750 QRasterPaintEngineState *s = state();
751 s->strokeFlags |= DirtyPen;
752 s->dirty |= DirtyPen;
753}
754
755/*!
756 \internal
757*/
758void QRasterPaintEngine::updatePen(const QPen &pen)
759{
760 Q_D(QRasterPaintEngine);
761 QRasterPaintEngineState *s = state();
762#ifdef QT_DEBUG_DRAW
763 qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
764#endif
765
766 Qt::PenStyle pen_style = qpen_style(pen);
767
768 s->lastPen = pen;
769 s->strokeFlags = 0;
770
771 s->penData.clip = d->clip();
772 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
773
774 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
775 || pen.brush().transform().type() >= QTransform::TxNone) {
776 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
777 }
778
779 // Slightly ugly handling of an uncommon case... We need to change
780 // the pen because it is reused in draw_midpoint to decide dashed
781 // or non-dashed.
782 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
783 pen_style = Qt::SolidLine;
784 s->lastPen.setStyle(Qt::SolidLine);
785 }
786
787 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
788 d->basicStroker.setCapStyle(qpen_capStyle(pen));
789 d->basicStroker.setMiterLimit(pen.miterLimit());
790
791 qreal penWidth = qpen_widthf(pen);
792 if (penWidth == 0)
793 d->basicStroker.setStrokeWidth(1);
794 else
795 d->basicStroker.setStrokeWidth(penWidth);
796
797 if(pen_style == Qt::SolidLine) {
798 s->stroker = &d->basicStroker;
799 } else if (pen_style != Qt::NoPen) {
800 if (!d->dashStroker)
801 d->dashStroker.reset(new QDashStroker(&d->basicStroker));
802 if (pen.isCosmetic()) {
803 d->dashStroker->setClipRect(d->deviceRect);
804 } else {
805 // ### I've seen this inverted devrect multiple places now...
806 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
807 d->dashStroker->setClipRect(clipRect);
808 }
809 d->dashStroker->setDashPattern(pen.dashPattern());
810 d->dashStroker->setDashOffset(pen.dashOffset());
811 s->stroker = d->dashStroker.data();
812 } else {
813 s->stroker = 0;
814 }
815
816 s->flags.fast_pen = pen_style > Qt::NoPen
817 && s->penData.blend
818 && !s->flags.antialiased
819 && (penWidth == 0 || (penWidth <= 1
820 && (s->matrix.type() <= QTransform::TxTranslate
821 || pen.isCosmetic())));
822
823 ensureState(); // needed because of tx_noshear...
824 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
825
826 s->strokeFlags = 0;
827}
828
829
830
831/*!
832 \internal
833*/
834void QRasterPaintEngine::brushOriginChanged()
835{
836 QRasterPaintEngineState *s = state();
837#ifdef QT_DEBUG_DRAW
838 qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
839#endif
840
841 s->fillFlags |= DirtyBrushOrigin;
842}
843
844
845/*!
846 \internal
847*/
848void QRasterPaintEngine::brushChanged()
849{
850 QRasterPaintEngineState *s = state();
851#ifdef QT_DEBUG_DRAW
852 qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
853#endif
854 s->fillFlags |= DirtyBrush;
855}
856
857
858
859
860/*!
861 \internal
862*/
863void QRasterPaintEngine::updateBrush(const QBrush &brush)
864{
865#ifdef QT_DEBUG_DRAW
866 qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
867#endif
868 Q_D(QRasterPaintEngine);
869 QRasterPaintEngineState *s = state();
870 // must set clip prior to setup, as setup uses it...
871 s->brushData.clip = d->clip();
872 s->brushData.setup(brush, s->intOpacity, s->composition_mode);
873 if (s->fillFlags & DirtyTransform
874 || brush.transform().type() >= QTransform::TxNone)
875 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
876 s->lastBrush = brush;
877 s->fillFlags = 0;
878}
879
880void QRasterPaintEngine::updateOutlineMapper()
881{
882 Q_D(QRasterPaintEngine);
883 d->outlineMapper->setMatrix(state()->matrix);
884}
885
886void QRasterPaintEngine::updateState()
887{
888 QRasterPaintEngineState *s = state();
889
890 if (s->dirty & DirtyTransform)
891 updateMatrix(s->matrix);
892
893 if (s->dirty & (DirtyPen|DirtyCompositionMode)) {
894 const QPainter::CompositionMode mode = s->composition_mode;
895 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
896 && (mode == QPainter::CompositionMode_Source
897 || (mode == QPainter::CompositionMode_SourceOver
898 && qAlpha(s->penData.solid.color) == 255));
899 }
900
901 s->dirty = 0;
902}
903
904
905/*!
906 \internal
907*/
908void QRasterPaintEngine::opacityChanged()
909{
910 QRasterPaintEngineState *s = state();
911
912#ifdef QT_DEBUG_DRAW
913 qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
914#endif
915
916 s->fillFlags |= DirtyOpacity;
917 s->strokeFlags |= DirtyOpacity;
918 s->pixmapFlags |= DirtyOpacity;
919 s->intOpacity = (int) (s->opacity * 256);
920}
921
922/*!
923 \internal
924*/
925void QRasterPaintEngine::compositionModeChanged()
926{
927 Q_D(QRasterPaintEngine);
928 QRasterPaintEngineState *s = state();
929
930#ifdef QT_DEBUG_DRAW
931 qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
932#endif
933
934 s->fillFlags |= DirtyCompositionMode;
935 s->dirty |= DirtyCompositionMode;
936
937 s->strokeFlags |= DirtyCompositionMode;
938 d->rasterBuffer->compositionMode = s->composition_mode;
939
940 d->recalculateFastImages();
941}
942
943/*!
944 \internal
945*/
946void QRasterPaintEngine::renderHintsChanged()
947{
948 QRasterPaintEngineState *s = state();
949
950#ifdef QT_DEBUG_DRAW
951 qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
952#endif
953
954 bool was_aa = s->flags.antialiased;
955 bool was_bilinear = s->flags.bilinear;
956
957 s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
958 s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
959
960 if (was_aa != s->flags.antialiased)
961 s->strokeFlags |= DirtyHints;
962
963 if (was_bilinear != s->flags.bilinear) {
964 s->strokeFlags |= DirtyPen;
965 s->fillFlags |= DirtyBrush;
966 }
967
968 Q_D(QRasterPaintEngine);
969 d->recalculateFastImages();
970}
971
972/*!
973 \internal
974*/
975void QRasterPaintEngine::transformChanged()
976{
977 QRasterPaintEngineState *s = state();
978
979#ifdef QT_DEBUG_DRAW
980 qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
981#endif
982
983 s->fillFlags |= DirtyTransform;
984 s->strokeFlags |= DirtyTransform;
985
986 s->dirty |= DirtyTransform;
987
988 Q_D(QRasterPaintEngine);
989 d->recalculateFastImages();
990}
991
992/*!
993 \internal
994*/
995void QRasterPaintEngine::clipEnabledChanged()
996{
997 QRasterPaintEngineState *s = state();
998
999#ifdef QT_DEBUG_DRAW
1000 qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
1001#endif
1002
1003 if (s->clip) {
1004 s->clip->enabled = s->clipEnabled;
1005 s->fillFlags |= DirtyClipEnabled;
1006 s->strokeFlags |= DirtyClipEnabled;
1007 s->pixmapFlags |= DirtyClipEnabled;
1008 }
1009}
1010
1011#ifdef Q_WS_QWS
1012void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
1013{
1014 rasterBuffer->prepare(device);
1015}
1016#endif
1017
1018void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
1019 const QImage &img,
1020 SrcOverBlendFunc func,
1021 const QRect &clip,
1022 int alpha,
1023 const QRect &sr)
1024{
1025 if (alpha == 0 || !clip.isValid())
1026 return;
1027
1028 Q_ASSERT(img.depth() >= 8);
1029
1030 int srcBPL = img.bytesPerLine();
1031 const uchar *srcBits = img.bits();
1032 int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
1033 int iw = img.width();
1034 int ih = img.height();
1035
1036 if (!sr.isEmpty()) {
1037 iw = sr.width();
1038 ih = sr.height();
1039 // Adjust the image according to the source offset...
1040 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1041 }
1042
1043 // adapt the x parameters
1044 int x = qRound(pt.x());
1045 int cx1 = clip.x();
1046 int cx2 = clip.x() + clip.width();
1047 if (x < cx1) {
1048 int d = cx1 - x;
1049 srcBits += srcSize * d;
1050 iw -= d;
1051 x = cx1;
1052 }
1053 if (x + iw > cx2) {
1054 int d = x + iw - cx2;
1055 iw -= d;
1056 }
1057 if (iw <= 0)
1058 return;
1059
1060 // adapt the y paremeters...
1061 int cy1 = clip.y();
1062 int cy2 = clip.y() + clip.height();
1063 int y = qRound(pt.y());
1064 if (y < cy1) {
1065 int d = cy1 - y;
1066 srcBits += srcBPL * d;
1067 ih -= d;
1068 y = cy1;
1069 }
1070 if (y + ih > cy2) {
1071 int d = y + ih - cy2;
1072 ih -= d;
1073 }
1074 if (ih <= 0)
1075 return;
1076
1077 // call the blend function...
1078 int dstSize = rasterBuffer->bytesPerPixel();
1079 int dstBPL = rasterBuffer->bytesPerLine();
1080 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1081 srcBits, srcBPL,
1082 iw, ih,
1083 alpha);
1084}
1085
1086
1087void QRasterPaintEnginePrivate::systemStateChanged()
1088{
1089 QRect clipRect(0, 0,
1090 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1091 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1092
1093 if (!systemClip.isEmpty()) {
1094 QRegion clippedDeviceRgn = systemClip & clipRect;
1095 deviceRect = clippedDeviceRgn.boundingRect();
1096 baseClip->setClipRegion(clippedDeviceRgn);
1097 } else {
1098 deviceRect = clipRect;
1099 baseClip->setClipRect(deviceRect);
1100 }
1101#ifdef QT_DEBUG_DRAW
1102 qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1103#endif
1104
1105 exDeviceRect = deviceRect;
1106
1107 Q_Q(QRasterPaintEngine);
1108 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1109 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1110 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1111}
1112
1113void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1114{
1115 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1116 return;
1117
1118 Q_Q(QRasterPaintEngine);
1119 bool bilinear = q->state()->flags.bilinear;
1120
1121 if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimise
1122 spanData->setupMatrix(b.transform() * m, bilinear);
1123 } else {
1124 if (m.type() <= QTransform::TxTranslate) {
1125 // specialize setupMatrix for translation matrices
1126 // to avoid needless matrix inversion
1127 spanData->m11 = 1;
1128 spanData->m12 = 0;
1129 spanData->m13 = 0;
1130 spanData->m21 = 0;
1131 spanData->m22 = 1;
1132 spanData->m23 = 0;
1133 spanData->m33 = 1;
1134 spanData->dx = -m.dx();
1135 spanData->dy = -m.dy();
1136 spanData->txop = m.type();
1137 spanData->bilinear = bilinear;
1138 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1139 spanData->adjustSpanMethods();
1140 } else {
1141 spanData->setupMatrix(m, bilinear);
1142 }
1143 }
1144}
1145
1146// #define QT_CLIPPING_RATIOS
1147
1148#ifdef QT_CLIPPING_RATIOS
1149int rectClips;
1150int regionClips;
1151int totalClips;
1152
1153static void checkClipRatios(QRasterPaintEnginePrivate *d)
1154{
1155 if (d->clip()->hasRectClip)
1156 rectClips++;
1157 if (d->clip()->hasRegionClip)
1158 regionClips++;
1159 totalClips++;
1160
1161 if ((totalClips % 5000) == 0) {
1162 printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1163 rectClips * 100.0 / (qreal) totalClips,
1164 regionClips * 100.0 / (qreal) totalClips,
1165 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1166 totalClips = 0;
1167 rectClips = 0;
1168 regionClips = 0;
1169 }
1170
1171}
1172#endif
1173
1174static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1175{
1176 if (s->flags.has_clip_ownership)
1177 delete s->clip;
1178 s->clip = 0;
1179 s->flags.has_clip_ownership = false;
1180}
1181
1182static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1183{
1184 s->fillFlags |= QPaintEngine::DirtyClipPath;
1185 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1186 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1187
1188 d->solid_color_filler.clip = d->clip();
1189 d->solid_color_filler.adjustSpanMethods();
1190
1191#ifdef QT_DEBUG_DRAW
1192 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1193#endif
1194
1195}
1196
1197
1198/*!
1199 \internal
1200*/
1201void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1202{
1203#ifdef QT_DEBUG_DRAW
1204 qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1205
1206 if (path.elements()) {
1207 for (int i=0; i<path.elementCount(); ++i) {
1208 qDebug() << " - " << path.elements()[i]
1209 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1210 }
1211 } else {
1212 for (int i=0; i<path.elementCount(); ++i) {
1213 qDebug() << " ---- "
1214 << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1215 }
1216 }
1217#endif
1218
1219 Q_D(QRasterPaintEngine);
1220 QRasterPaintEngineState *s = state();
1221
1222 const qreal *points = path.points();
1223 const QPainterPath::ElementType *types = path.elements();
1224
1225 // There are some cases that are not supported by clip(QRect)
1226 if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1227 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1228 if (s->matrix.type() <= QTransform::TxTranslate
1229 && ((path.shape() == QVectorPath::RectangleHint)
1230 || (isRect(points, path.elementCount())
1231 && (!types || (types[0] == QPainterPath::MoveToElement
1232 && types[1] == QPainterPath::LineToElement
1233 && types[2] == QPainterPath::LineToElement
1234 && types[3] == QPainterPath::LineToElement))))) {
1235#ifdef QT_DEBUG_DRAW
1236 qDebug() << " --- optimizing vector clip to rect clip...";
1237#endif
1238
1239 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1240 clip(r.toRect(), op);
1241 return;
1242 }
1243 }
1244
1245 if (op == Qt::NoClip) {
1246 qrasterpaintengine_state_setNoClip(s);
1247
1248 } else {
1249 QClipData *base = d->baseClip.data();
1250
1251 // Intersect with current clip when available...
1252 if (op == Qt::IntersectClip && s->clip)
1253 base = s->clip;
1254
1255 // We always intersect, except when there is nothing to
1256 // intersect with, in which case we simplify the operation to
1257 // a replace...
1258 Qt::ClipOperation isectOp = Qt::IntersectClip;
1259 if (base == 0)
1260 isectOp = Qt::ReplaceClip;
1261
1262 QClipData *newClip = new QClipData(d->rasterBuffer->height());
1263 newClip->initialize();
1264 ClipData clipData = { base, newClip, isectOp };
1265 ensureOutlineMapper();
1266 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1267
1268 newClip->fixup();
1269
1270 if (op == Qt::UniteClip) {
1271 // merge clips
1272 QClipData *result = new QClipData(d->rasterBuffer->height());
1273 QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1274 qt_merge_clip(current, newClip, result);
1275 result->fixup();
1276 delete newClip;
1277 if (!s->clip)
1278 delete current;
1279 newClip = result;
1280 }
1281
1282 if (s->flags.has_clip_ownership)
1283 delete s->clip;
1284
1285 s->clip = newClip;
1286 s->flags.has_clip_ownership = true;
1287 }
1288 qrasterpaintengine_dirty_clip(d, s);
1289}
1290
1291
1292
1293/*!
1294 \internal
1295*/
1296void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1297{
1298#ifdef QT_DEBUG_DRAW
1299 qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1300#endif
1301
1302 Q_D(QRasterPaintEngine);
1303 QRasterPaintEngineState *s = state();
1304
1305 if (op == Qt::NoClip) {
1306 qrasterpaintengine_state_setNoClip(s);
1307
1308 } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1309 QPaintEngineEx::clip(rect, op);
1310 return;
1311
1312 } else if (op == Qt::ReplaceClip || s->clip == 0) {
1313
1314 // No current clip, hence we intersect with sysclip and be
1315 // done with it...
1316 QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
1317 QRegion clipRegion = systemClip();
1318 QClipData *clip = new QClipData(d->rasterBuffer->height());
1319
1320 if (clipRegion.isEmpty())
1321 clip->setClipRect(clipRect);
1322 else
1323 clip->setClipRegion(clipRegion & clipRect);
1324
1325 if (s->flags.has_clip_ownership)
1326 delete s->clip;
1327
1328 s->clip = clip;
1329 s->clip->enabled = true;
1330 s->flags.has_clip_ownership = true;
1331
1332 } else { // intersect clip with current clip
1333 QClipData *base = s->clip;
1334
1335 Q_ASSERT(base);
1336 if (base->hasRectClip || base->hasRegionClip) {
1337 QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
1338 if (!s->flags.has_clip_ownership) {
1339 s->clip = new QClipData(d->rasterBuffer->height());
1340 s->flags.has_clip_ownership = true;
1341 }
1342 if (base->hasRectClip)
1343 s->clip->setClipRect(base->clipRect & clipRect);
1344 else
1345 s->clip->setClipRegion(base->clipRegion & clipRect);
1346 s->clip->enabled = true;
1347 } else {
1348 QPaintEngineEx::clip(rect, op);
1349 return;
1350 }
1351 }
1352 qrasterpaintengine_dirty_clip(d, s);
1353}
1354
1355
1356/*!
1357 \internal
1358*/
1359void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1360{
1361#ifdef QT_DEBUG_DRAW
1362 qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1363#endif
1364
1365 Q_D(QRasterPaintEngine);
1366
1367 if (region.rectCount() == 1) {
1368 clip(region.boundingRect(), op);
1369 return;
1370 }
1371
1372 QRasterPaintEngineState *s = state();
1373 const QClipData *clip = d->clip();
1374 const QClipData *baseClip = d->baseClip.data();
1375
1376 if (op == Qt::NoClip) {
1377 qrasterpaintengine_state_setNoClip(s);
1378 } else if (s->matrix.type() > QTransform::TxScale
1379 || op == Qt::UniteClip
1380 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1381 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1382 QPaintEngineEx::clip(region, op);
1383 } else {
1384 const QClipData *curClip;
1385 QClipData *newClip;
1386
1387 if (op == Qt::IntersectClip)
1388 curClip = clip;
1389 else
1390 curClip = baseClip;
1391
1392 if (s->flags.has_clip_ownership) {
1393 newClip = s->clip;
1394 Q_ASSERT(newClip);
1395 } else {
1396 newClip = new QClipData(d->rasterBuffer->height());
1397 s->clip = newClip;
1398 s->flags.has_clip_ownership = true;
1399 }
1400
1401 QRegion r = s->matrix.map(region);
1402 if (curClip->hasRectClip)
1403 newClip->setClipRegion(r & curClip->clipRect);
1404 else if (curClip->hasRegionClip)
1405 newClip->setClipRegion(r & curClip->clipRegion);
1406
1407 qrasterpaintengine_dirty_clip(d, s);
1408 }
1409}
1410
1411/*!
1412 \internal
1413*/
1414void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1415{
1416#ifdef QT_DEBUG_DRAW
1417 qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1418#endif
1419
1420 if (!fillData->blend)
1421 return;
1422
1423 Q_D(QRasterPaintEngine);
1424
1425 const QRectF controlPointRect = path.controlPointRect();
1426
1427 QRasterPaintEngineState *s = state();
1428 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1429 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1430 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1431 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1432 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1433 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1434
1435 if (!s->flags.antialiased && !do_clip) {
1436 d->initializeRasterizer(fillData);
1437 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1438 return;
1439 }
1440
1441 ensureOutlineMapper();
1442 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1443}
1444
1445static void fillRect_normalized(const QRect &r, QSpanData *data,
1446 QRasterPaintEnginePrivate *pe)
1447{
1448 int x1, x2, y1, y2;
1449
1450 bool rectClipped = true;
1451
1452 if (data->clip) {
1453 x1 = qMax(r.x(), data->clip->xmin);
1454 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1455 y1 = qMax(r.y(), data->clip->ymin);
1456 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1457 rectClipped = data->clip->hasRectClip;
1458
1459 } else if (pe) {
1460 x1 = qMax(r.x(), pe->deviceRect.x());
1461 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1462 y1 = qMax(r.y(), pe->deviceRect.y());
1463 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1464 } else {
1465 x1 = qMax(r.x(), 0);
1466 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1467 y1 = qMax(r.y(), 0);
1468 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1469 }
1470
1471 if (x2 <= x1 || y2 <= y1)
1472 return;
1473
1474 const int width = x2 - x1;
1475 const int height = y2 - y1;
1476
1477 bool isUnclipped = rectClipped
1478 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1479
1480 if (pe && isUnclipped) {
1481 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1482
1483 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1484 || (mode == QPainter::CompositionMode_SourceOver
1485 && qAlpha(data->solid.color) == 255)))
1486 {
1487 data->fillRect(data->rasterBuffer, x1, y1, width, height,
1488 data->solid.color);
1489 return;
1490 }
1491 }
1492
1493 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1494
1495 const int nspans = 256;
1496 QT_FT_Span spans[nspans];
1497
1498 Q_ASSERT(data->blend);
1499 int y = y1;
1500 while (y < y2) {
1501 int n = qMin(nspans, y2 - y);
1502 int i = 0;
1503 while (i < n) {
1504 spans[i].x = x1;
1505 spans[i].len = width;
1506 spans[i].y = y + i;
1507 spans[i].coverage = 255;
1508 ++i;
1509 }
1510
1511 blend(n, spans, data);
1512 y += n;
1513 }
1514}
1515
1516/*!
1517 \reimp
1518*/
1519void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1520{
1521#ifdef QT_DEBUG_DRAW
1522 qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1523#endif
1524 Q_D(QRasterPaintEngine);
1525 QRasterPaintEngineState *s = state();
1526
1527 // Fill
1528 ensureBrush();
1529 if (s->brushData.blend) {
1530 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1531 const QRect *r = rects;
1532 const QRect *lastRect = rects + rectCount;
1533
1534 int offset_x = int(s->matrix.dx());
1535 int offset_y = int(s->matrix.dy());
1536 while (r < lastRect) {
1537 QRect rect = r->normalized();
1538 QRect rr = rect.translated(offset_x, offset_y);
1539 fillRect_normalized(rr, &s->brushData, d);
1540 ++r;
1541 }
1542 } else {
1543 QRectVectorPath path;
1544 for (int i=0; i<rectCount; ++i) {
1545 path.set(rects[i]);
1546 fill(path, s->brush);
1547 }
1548 }
1549 }
1550
1551 ensurePen();
1552 if (s->penData.blend) {
1553 if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
1554 const QRect *r = rects;
1555 const QRect *lastRect = rects + rectCount;
1556 while (r < lastRect) {
1557 int left = r->x();
1558 int right = r->x() + r->width();
1559 int top = r->y();
1560 int bottom = r->y() + r->height();
1561
1562#ifdef Q_WS_MAC
1563 int pts[] = { top, left,
1564 top, right,
1565 bottom, right,
1566 bottom, left };
1567#else
1568 int pts[] = { left, top,
1569 right, top,
1570 right, bottom,
1571 left, bottom };
1572#endif
1573
1574 strokePolygonCosmetic((QPoint *) pts, 4, WindingMode);
1575 ++r;
1576 }
1577 } else {
1578 QRectVectorPath path;
1579 for (int i = 0; i < rectCount; ++i) {
1580 path.set(rects[i]);
1581 stroke(path, s->pen);
1582 }
1583 }
1584 }
1585}
1586
1587/*!
1588 \reimp
1589*/
1590void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1591{
1592#ifdef QT_DEBUG_DRAW
1593 qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1594#endif
1595#ifdef QT_FAST_SPANS
1596 Q_D(QRasterPaintEngine);
1597 QRasterPaintEngineState *s = state();
1598
1599 ensureState();
1600
1601 if (s->flags.tx_noshear) {
1602 ensureBrush();
1603 if (s->brushData.blend) {
1604 d->initializeRasterizer(&s->brushData);
1605 for (int i = 0; i < rectCount; ++i) {
1606 const QRectF &rect = rects[i].normalized();
1607 if (rect.isEmpty())
1608 continue;
1609 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1610 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1611 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1612 }
1613 }
1614
1615 ensurePen();
1616 if (s->penData.blend) {
1617 qreal width = s->pen.isCosmetic()
1618 ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF())
1619 : s->lastPen.widthF() * s->txscale;
1620
1621 if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
1622 for (int i = 0; i < rectCount; ++i) {
1623 const QRectF &r = rects[i];
1624 qreal left = r.x();
1625 qreal right = r.x() + r.width();
1626 qreal top = r.y();
1627 qreal bottom = r.y() + r.height();
1628 qreal pts[] = { left, top,
1629 right, top,
1630 right, bottom,
1631 left, bottom };
1632 strokePolygonCosmetic((QPointF *) pts, 4, WindingMode);
1633 }
1634 } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) {
1635 d->initializeRasterizer(&s->penData);
1636
1637 for (int i = 0; i < rectCount; ++i) {
1638 const QRectF &rect = rects[i].normalized();
1639 if (rect.isEmpty()) {
1640 qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() };
1641 QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint);
1642 QPaintEngineEx::stroke(vp, s->lastPen);
1643 } else {
1644 const QPointF tl = s->matrix.map(rect.topLeft());
1645 const QPointF tr = s->matrix.map(rect.topRight());
1646 const QPointF bl = s->matrix.map(rect.bottomLeft());
1647 const QPointF br = s->matrix.map(rect.bottomRight());
1648 const qreal w = width / (rect.width() * s->txscale);
1649 const qreal h = width / (rect.height() * s->txscale);
1650 d->rasterizer->rasterizeLine(tl, tr, w); // top
1651 d->rasterizer->rasterizeLine(bl, br, w); // bottom
1652 d->rasterizer->rasterizeLine(bl, tl, h); // left
1653 d->rasterizer->rasterizeLine(br, tr, h); // right
1654 }
1655 }
1656 } else {
1657 for (int i = 0; i < rectCount; ++i) {
1658 const QRectF &r = rects[i];
1659 qreal left = r.x();
1660 qreal right = r.x() + r.width();
1661 qreal top = r.y();
1662 qreal bottom = r.y() + r.height();
1663 qreal pts[] = { left, top,
1664 right, top,
1665 right, bottom,
1666 left, bottom,
1667 left, top };
1668 QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
1669 QPaintEngineEx::stroke(vp, s->lastPen);
1670 }
1671 }
1672 }
1673
1674 return;
1675 }
1676#endif // QT_FAST_SPANS
1677 QPaintEngineEx::drawRects(rects, rectCount);
1678}
1679
1680
1681/*!
1682 \internal
1683*/
1684void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1685{
1686 QRasterPaintEngineState *s = state();
1687 ensurePen(pen);
1688 if (!s->penData.blend)
1689 return;
1690
1691 if (s->flags.fast_pen && !path.isCurved()
1692 && s->lastPen.brush().isOpaque()) {
1693 int count = path.elementCount();
1694 QPointF *points = (QPointF *) path.points();
1695 const QPainterPath::ElementType *types = path.elements();
1696 if (types) {
1697 int first = 0;
1698 int last;
1699 while (first < count) {
1700 while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
1701 last = first + 1;
1702 while (last < count && types[last] == QPainterPath::LineToElement) ++last;
1703 strokePolygonCosmetic(points + first, last - first,
1704 path.hasImplicitClose() && last == count // only close last one..
1705 ? WindingMode
1706 : PolylineMode);
1707 first = last;
1708 }
1709 } else {
1710 strokePolygonCosmetic(points, count,
1711 path.hasImplicitClose()
1712 ? WindingMode
1713 : PolylineMode);
1714 }
1715
1716 } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1717 qreal width = s->lastPen.isCosmetic()
1718 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1719 : qpen_widthf(s->lastPen) * s->txscale;
1720 int dashIndex = 0;
1721 qreal dashOffset = s->lastPen.dashOffset();
1722 bool inDash = true;
1723 qreal patternLength = 0;
1724 const QVector<qreal> pattern = s->lastPen.dashPattern();
1725 for (int i = 0; i < pattern.size(); ++i)
1726 patternLength += pattern.at(i);
1727
1728 if (patternLength > 0) {
1729 int n = qFloor(dashOffset / patternLength);
1730 dashOffset -= n * patternLength;
1731 while (dashOffset > pattern.at(dashIndex)) {
1732 dashOffset -= pattern.at(dashIndex);
1733 dashIndex = (dashIndex + 1) % pattern.size();
1734 inDash = !inDash;
1735 }
1736 }
1737
1738 Q_D(QRasterPaintEngine);
1739 d->initializeRasterizer(&s->penData);
1740 int lineCount = path.elementCount() / 2;
1741 const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1742
1743 for (int i = 0; i < lineCount; ++i) {
1744 dashOffset = s->lastPen.dashOffset();
1745 if (lines[i].p1() == lines[i].p2()) {
1746 if (s->lastPen.capStyle() != Qt::FlatCap) {
1747 QPointF p = lines[i].p1();
1748 QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1749 QPointF(p.x() + width*0.5, p.y())));
1750 d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1751 }
1752 continue;
1753 }
1754
1755 const QLineF line = s->matrix.map(lines[i]);
1756 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1757 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1758 width / line.length(),
1759 s->lastPen.capStyle() == Qt::SquareCap);
1760 } else {
1761 d->rasterizeLine_dashed(line, width,
1762 &dashIndex, &dashOffset, &inDash);
1763 }
1764 }
1765 }
1766 else
1767 QPaintEngineEx::stroke(path, pen);
1768}
1769
1770static inline QRect toNormalizedFillRect(const QRectF &rect)
1771{
1772 int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1773 int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1774 int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1775 int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1776
1777 if (x2 < x1)
1778 qSwap(x1, x2);
1779 if (y2 < y1)
1780 qSwap(y1, y2);
1781
1782 return QRect(x1, y1, x2 - x1, y2 - y1);
1783}
1784
1785/*!
1786 \internal
1787*/
1788void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1789{
1790 if (path.isEmpty())
1791 return;
1792#ifdef QT_DEBUG_DRAW
1793 QRectF rf = path.controlPointRect();
1794 qDebug() << "QRasterPaintEngine::fill(): "
1795 << "size=" << path.elementCount()
1796 << ", hints=" << hex << path.hints()
1797 << rf << brush;
1798#endif
1799
1800 Q_D(QRasterPaintEngine);
1801 QRasterPaintEngineState *s = state();
1802
1803 ensureBrush(brush);
1804 if (!s->brushData.blend)
1805 return;
1806
1807 if (path.shape() == QVectorPath::RectangleHint) {
1808 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1809 const qreal *p = path.points();
1810 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1811 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1812 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1813 return;
1814 }
1815 ensureState();
1816 if (s->flags.tx_noshear) {
1817 d->initializeRasterizer(&s->brushData);
1818 // ### Is normalizing really nessesary here?
1819 const qreal *p = path.points();
1820 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1821 if (!r.isEmpty()) {
1822 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1823 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1824 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1825 }
1826 return;
1827 }
1828 }
1829
1830 if (path.shape() == QVectorPath::EllipseHint) {
1831 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1832 const qreal *p = path.points();
1833 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1834 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1835 QRectF r = s->matrix.mapRect(QRectF(tl, br));
1836
1837 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
1838 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
1839 const QRect brect = QRect(int(r.x()), int(r.y()),
1840 int_dim(r.x(), r.width()),
1841 int_dim(r.y(), r.height()));
1842 if (brect == r) {
1843 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
1844 &s->penData, &s->brushData);
1845 return;
1846 }
1847 }
1848 }
1849
1850 // ### Optimize for non transformed ellipses and rectangles...
1851 QRectF cpRect = path.controlPointRect();
1852 const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1853 ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1854
1855 // ### Falcon
1856// const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1857// || deviceRect.right() > QT_RASTER_COORD_LIMIT
1858// || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1859// || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1860
1861 // ### Falonc: implement....
1862// if (!s->flags.antialiased && !do_clip) {
1863// d->initializeRasterizer(&s->brushData);
1864// d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1865// return;
1866// }
1867
1868 ensureOutlineMapper();
1869 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1870}
1871
1872void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1873{
1874 Q_D(QRasterPaintEngine);
1875 QRasterPaintEngineState *s = state();
1876
1877 if (!s->flags.antialiased) {
1878 uint txop = s->matrix.type();
1879 if (txop == QTransform::TxNone) {
1880 fillRect_normalized(toNormalizedFillRect(r), data, d);
1881 return;
1882 } else if (txop == QTransform::TxTranslate) {
1883 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1884 fillRect_normalized(rr, data, d);
1885 return;
1886 } else if (txop == QTransform::TxScale) {
1887 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1888 fillRect_normalized(rr, data, d);
1889 return;
1890 }
1891 }
1892 ensureState();
1893 if (s->flags.tx_noshear) {
1894 d->initializeRasterizer(data);
1895 QRectF nr = r.normalized();
1896 if (!nr.isEmpty()) {
1897 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1898 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1899 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1900 }
1901 return;
1902 }
1903
1904 QPainterPath path;
1905 path.addRect(r);
1906 ensureOutlineMapper();
1907 fillPath(path, data);
1908}
1909
1910/*!
1911 \reimp
1912*/
1913void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1914{
1915#ifdef QT_DEBUG_DRAW
1916 qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1917#endif
1918 QRasterPaintEngineState *s = state();
1919
1920 ensureBrush(brush);
1921 if (!s->brushData.blend)
1922 return;
1923
1924 fillRect(r, &s->brushData);
1925}
1926
1927/*!
1928 \reimp
1929*/
1930void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1931{
1932#ifdef QT_DEBUG_DRAW
1933 qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1934#endif
1935 Q_D(QRasterPaintEngine);
1936 QRasterPaintEngineState *s = state();
1937
1938 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1939 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1940 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1941 return;
1942 }
1943 d->solid_color_filler.clip = d->clip();
1944 d->solid_color_filler.adjustSpanMethods();
1945 fillRect(r, &d->solid_color_filler);
1946}
1947
1948static inline bool isAbove(const QPointF *a, const QPointF *b)
1949{
1950 return a->y() < b->y();
1951}
1952
1953static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1954{
1955 Q_ASSERT(upper);
1956 Q_ASSERT(lower);
1957
1958 Q_ASSERT(pointCount >= 2);
1959
1960 QVector<const QPointF *> sorted;
1961 sorted.reserve(pointCount);
1962
1963 upper->reserve(pointCount * 3 / 4);
1964 lower->reserve(pointCount * 3 / 4);
1965
1966 for (int i = 0; i < pointCount; ++i)
1967 sorted << points + i;
1968
1969 qSort(sorted.begin(), sorted.end(), isAbove);
1970
1971 qreal splitY = sorted.at(sorted.size() / 2)->y();
1972
1973 const QPointF *end = points + pointCount;
1974 const QPointF *last = end - 1;
1975
1976 QVector<QPointF> *bin[2] = { upper, lower };
1977
1978 for (const QPointF *p = points; p < end; ++p) {
1979 int side = p->y() < splitY;
1980 int lastSide = last->y() < splitY;
1981
1982 if (side != lastSide) {
1983 if (qFuzzyCompare(p->y(), splitY)) {
1984 bin[!side]->append(*p);
1985 } else if (qFuzzyCompare(last->y(), splitY)) {
1986 bin[side]->append(*last);
1987 } else {
1988 QPointF delta = *p - *last;
1989 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1990
1991 bin[0]->append(intersection);
1992 bin[1]->append(intersection);
1993 }
1994 }
1995
1996 bin[side]->append(*p);
1997
1998 last = p;
1999 }
2000
2001 // give up if we couldn't reduce the point count
2002 return upper->size() < pointCount && lower->size() < pointCount;
2003}
2004
2005/*!
2006 \internal
2007 */
2008void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
2009{
2010 Q_D(QRasterPaintEngine);
2011 QRasterPaintEngineState *s = state();
2012
2013 const int maxPoints = 0xffff;
2014
2015 // max amount of points that raster engine can reliably handle
2016 if (pointCount > maxPoints) {
2017 QVector<QPointF> upper, lower;
2018
2019 if (splitPolygon(points, pointCount, &upper, &lower)) {
2020 fillPolygon(upper.constData(), upper.size(), mode);
2021 fillPolygon(lower.constData(), lower.size(), mode);
2022 } else
2023 qWarning("Polygon too complex for filling.");
2024
2025 return;
2026 }
2027
2028 // Compose polygon fill..,
2029 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
2030 ensureOutlineMapper();
2031 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
2032
2033 // scanconvert.
2034 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2035 &s->brushData);
2036 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
2037}
2038
2039/*!
2040 \reimp
2041*/
2042void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
2043{
2044 Q_D(QRasterPaintEngine);
2045 QRasterPaintEngineState *s = state();
2046
2047#ifdef QT_DEBUG_DRAW
2048 qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
2049 for (int i=0; i<pointCount; ++i)
2050 qDebug() << " - " << points[i];
2051#endif
2052 Q_ASSERT(pointCount >= 2);
2053
2054 if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
2055 QRectF r(points[0], points[2]);
2056 drawRects(&r, 1);
2057 return;
2058 }
2059
2060 ensurePen();
2061 ensureBrush();
2062 if (mode != PolylineMode) {
2063 // Do the fill...
2064 if (s->brushData.blend) {
2065 d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
2066 fillPolygon(points, pointCount, mode);
2067 d->outlineMapper->setCoordinateRounding(false);
2068 }
2069 }
2070
2071 // Do the outline...
2072 if (s->penData.blend) {
2073 if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
2074 strokePolygonCosmetic(points, pointCount, mode);
2075 else {
2076 QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
2077 QPaintEngineEx::stroke(vp, s->lastPen);
2078 }
2079 }
2080}
2081
2082/*!
2083 \reimp
2084*/
2085void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
2086{
2087 Q_D(QRasterPaintEngine);
2088 QRasterPaintEngineState *s = state();
2089
2090#ifdef QT_DEBUG_DRAW
2091 qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
2092 for (int i=0; i<pointCount; ++i)
2093 qDebug() << " - " << points[i];
2094#endif
2095 Q_ASSERT(pointCount >= 2);
2096 if (mode != PolylineMode && isRect((int *) points, pointCount)) {
2097 QRect r(points[0].x(),
2098 points[0].y(),
2099 points[2].x() - points[0].x(),
2100 points[2].y() - points[0].y());
2101 drawRects(&r, 1);
2102 return;
2103 }
2104
2105 ensureState();
2106 ensurePen();
2107 if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) {
2108 // this calls the float version
2109 QPaintEngineEx::drawPolygon(points, pointCount, mode);
2110 return;
2111 }
2112
2113 // Do the fill
2114 if (mode != PolylineMode) {
2115 ensureBrush();
2116 if (s->brushData.blend) {
2117 // Compose polygon fill..,
2118 ensureOutlineMapper();
2119 d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
2120 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
2121 d->outlineMapper->moveTo(*points);
2122 const QPoint *p = points;
2123 const QPoint *ep = points + pointCount - 1;
2124 do {
2125 d->outlineMapper->lineTo(*(++p));
2126 } while (p < ep);
2127 d->outlineMapper->endOutline();
2128
2129 // scanconvert.
2130 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2131 &s->brushData);
2132 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2133 d->outlineMapper->setCoordinateRounding(false);
2134 }
2135 }
2136
2137 // Do the outline...
2138 if (s->penData.blend) {
2139 if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
2140 strokePolygonCosmetic(points, pointCount, mode);
2141 else {
2142 int count = pointCount * 2;
2143 QVarLengthArray<qreal> fpoints(count);
2144#ifdef Q_WS_MAC
2145 for (int i=0; i<count; i+=2) {
2146 fpoints[i] = ((int *) points)[i+1];
2147 fpoints[i+1] = ((int *) points)[i];
2148 }
2149#else
2150 for (int i=0; i<count; ++i)
2151 fpoints[i] = ((int *) points)[i];
2152#endif
2153 QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2154 QPaintEngineEx::stroke(vp, s->lastPen);
2155 }
2156 }
2157}
2158
2159/*!
2160 \internal
2161*/
2162void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode)
2163{
2164 Q_D(QRasterPaintEngine);
2165 QRasterPaintEngineState *s = state();
2166
2167 Q_ASSERT(s->penData.blend);
2168 Q_ASSERT(s->flags.fast_pen);
2169
2170 bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
2171
2172 // Use fast path for 0 width / trivial pens.
2173 QIntRect devRect;
2174 devRect.set(d->deviceRect);
2175
2176 LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
2177 ? LineDrawIncludeLastPixel
2178 : LineDrawNormal);
2179 int dashOffset = int(s->lastPen.dashOffset());
2180
2181 const QPointF offs(aliasedCoordinateDelta, aliasedCoordinateDelta);
2182
2183 // Draw all the line segments.
2184 for (int i=1; i<pointCount; ++i) {
2185
2186 QPointF lp1 = points[i-1] * s->matrix + offs;
2187 QPointF lp2 = points[i] * s->matrix + offs;
2188
2189 const QRectF brect(lp1, lp2);
2190 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2191 if (qpen_style(s->lastPen) == Qt::SolidLine) {
2192 drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
2193 qFloor(lp2.x()), qFloor(lp2.y()),
2194 penBlend, &s->penData,
2195 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2196 devRect);
2197 } else {
2198 drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
2199 qFloor(lp2.x()), qFloor(lp2.y()),
2200 &s->lastPen,
2201 penBlend, &s->penData,
2202 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2203 devRect, &dashOffset);
2204 }
2205 }
2206
2207 // Polygons are implicitly closed.
2208 if (needs_closing) {
2209 QPointF lp1 = points[pointCount-1] * s->matrix + offs;
2210 QPointF lp2 = points[0] * s->matrix + offs;
2211
2212 const QRectF brect(lp1, lp2);
2213 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2214 if (qpen_style(s->lastPen) == Qt::SolidLine) {
2215 drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
2216 qFloor(lp2.x()), qFloor(lp2.y()),
2217 penBlend, &s->penData,
2218 LineDrawIncludeLastPixel,
2219 devRect);
2220 } else {
2221 drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
2222 qFloor(lp2.x()), qFloor(lp2.y()),
2223 &s->lastPen,
2224 penBlend, &s->penData,
2225 LineDrawIncludeLastPixel,
2226 devRect, &dashOffset);
2227 }
2228 }
2229
2230}
2231
2232/*!
2233 \internal
2234*/
2235void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode)
2236{
2237 Q_D(QRasterPaintEngine);
2238 QRasterPaintEngineState *s = state();
2239
2240 // We assert here because this function is called from drawRects
2241 // and drawPolygon and they already do ensurePen(), so we skip that
2242 // here to avoid duplicate checks..
2243 Q_ASSERT(s->penData.blend);
2244
2245 bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
2246
2247 QIntRect devRect;
2248 devRect.set(d->deviceRect);
2249
2250 LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
2251 ? LineDrawIncludeLastPixel
2252 : LineDrawNormal);
2253
2254 int m11 = int(s->matrix.m11());
2255 int m22 = int(s->matrix.m22());
2256 int dx = int(s->matrix.dx());
2257 int dy = int(s->matrix.dy());
2258 int m13 = int(s->matrix.m13());
2259 int m23 = int(s->matrix.m23());
2260 bool affine = !m13 && !m23;
2261
2262 int dashOffset = int(s->lastPen.dashOffset());
2263
2264 if (affine) {
2265 // Draw all the line segments.
2266 for (int i=1; i<pointCount; ++i) {
2267 const QPoint lp1 = points[i-1] * s->matrix;
2268 const QPoint lp2 = points[i] * s->matrix;
2269 const QRect brect(lp1, lp2);
2270 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2271
2272 if (qpen_style(s->lastPen) == Qt::SolidLine)
2273 drawLine_midpoint_i(lp1.x(), lp1.y(),
2274 lp2.x(), lp2.y(),
2275 penBlend, &s->penData,
2276 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2277 devRect);
2278 else
2279 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
2280 lp2.x(), lp2.y(),
2281 &s->lastPen,
2282 penBlend, &s->penData,
2283 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2284 devRect, &dashOffset);
2285
2286 }
2287
2288 // Polygons are implicitly closed.
2289 if (needs_closing) {
2290 const QPoint lp1 = points[pointCount - 1] * s->matrix;
2291 const QPoint lp2 = points[0] * s->matrix;
2292 const QRect brect(lp1, lp2);
2293 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2294
2295 if (qpen_style(s->lastPen) == Qt::SolidLine)
2296 drawLine_midpoint_i(lp1.x(), lp1.y(),
2297 lp2.x(), lp2.y(),
2298 penBlend, &s->penData, LineDrawIncludeLastPixel,
2299 devRect);
2300 else
2301 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
2302 lp2.x(), lp2.y(),
2303 &s->lastPen,
2304 penBlend, &s->penData, LineDrawIncludeLastPixel,
2305 devRect, &dashOffset);
2306 }
2307 } else {
2308 // Draw all the line segments.
2309 for (int i=1; i<pointCount; ++i) {
2310 int x1 = points[i-1].x() * m11 + dx;
2311 int y1 = points[i-1].y() * m22 + dy;
2312 qreal w = m13*points[i-1].x() + m23*points[i-1].y() + 1.;
2313 w = 1/w;
2314 x1 = int(x1*w);
2315 y1 = int(y1*w);
2316 int x2 = points[i].x() * m11 + dx;
2317 int y2 = points[i].y() * m22 + dy;
2318 w = m13*points[i].x() + m23*points[i].y() + 1.;
2319 w = 1/w;
2320 x2 = int(x2*w);
2321 y2 = int(y2*w);
2322
2323 const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2324 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2325 if (qpen_style(s->lastPen) == Qt::SolidLine)
2326 drawLine_midpoint_i(x1, y1, x2, y2,
2327 penBlend, &s->penData,
2328 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2329 devRect);
2330 else
2331 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
2332 &s->lastPen,
2333 penBlend, &s->penData,
2334 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2335 devRect, &dashOffset);
2336
2337 }
2338
2339 int x1 = points[pointCount-1].x() * m11 + dx;
2340 int y1 = points[pointCount-1].y() * m22 + dy;
2341 qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.;
2342 w = 1/w;
2343 x1 = int(x1*w);
2344 y1 = int(y1*w);
2345 int x2 = points[0].x() * m11 + dx;
2346 int y2 = points[0].y() * m22 + dy;
2347 w = m13*points[0].x() + m23*points[0].y() + 1.;
2348 w = 1/w;
2349 x2 = int(x2 * w);
2350 y2 = int(y2 * w);
2351 // Polygons are implicitly closed.
2352
2353 if (needs_closing) {
2354 const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2355 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2356 if (qpen_style(s->lastPen) == Qt::SolidLine)
2357 drawLine_midpoint_i(x1, y1, x2, y2,
2358 penBlend, &s->penData, LineDrawIncludeLastPixel,
2359 devRect);
2360 else
2361 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
2362 &s->lastPen,
2363 penBlend, &s->penData, LineDrawIncludeLastPixel,
2364 devRect, &dashOffset);
2365 }
2366 }
2367}
2368
2369/*!
2370 \internal
2371*/
2372void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2373{
2374#ifdef QT_DEBUG_DRAW
2375 qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2376#endif
2377
2378 if (pixmap.data->classId() == QPixmapData::RasterClass) {
2379 const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2380 if (image.depth() == 1) {
2381 Q_D(QRasterPaintEngine);
2382 QRasterPaintEngineState *s = state();
2383 if (s->matrix.type() <= QTransform::TxTranslate) {
2384 ensurePen();
2385 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2386 } else {
2387 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2388 }
2389 } else {
2390 QRasterPaintEngine::drawImage(pos, image);
2391 }
2392 } else {
2393 const QImage image = pixmap.toImage();
2394 if (pixmap.depth() == 1) {
2395 Q_D(QRasterPaintEngine);
2396 QRasterPaintEngineState *s = state();
2397 if (s->matrix.type() <= QTransform::TxTranslate) {
2398 ensurePen();
2399 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2400 } else {
2401 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2402 }
2403 } else {
2404 QRasterPaintEngine::drawImage(pos, image);
2405 }
2406 }
2407}
2408
2409/*!
2410 \reimp
2411*/
2412void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2413{
2414#ifdef QT_DEBUG_DRAW
2415 qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2416#endif
2417
2418 if (pixmap.data->classId() == QPixmapData::RasterClass) {
2419 const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2420 if (image.depth() == 1) {
2421 Q_D(QRasterPaintEngine);
2422 QRasterPaintEngineState *s = state();
2423 if (s->matrix.type() <= QTransform::TxTranslate
2424 && r.size() == sr.size()
2425 && r.size() == pixmap.size()) {
2426 ensurePen();
2427 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2428 return;
2429 } else {
2430 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2431 }
2432 } else {
2433 drawImage(r, image, sr);
2434 }
2435 } else {
2436 const QImage image = pixmap.toImage();
2437 if (image.depth() == 1) {
2438 Q_D(QRasterPaintEngine);
2439 QRasterPaintEngineState *s = state();
2440 if (s->matrix.type() <= QTransform::TxTranslate
2441 && r.size() == sr.size()
2442 && r.size() == pixmap.size()) {
2443 ensurePen();
2444 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2445 return;
2446 } else {
2447 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2448 }
2449 } else {
2450 drawImage(r, image, sr);
2451 }
2452 }
2453}
2454
2455// assumes that rect has positive width and height
2456static inline const QRect toRect_normalized(const QRectF &rect)
2457{
2458 const int x = qRound(rect.x());
2459 const int y = qRound(rect.y());
2460 const int w = int(rect.width() + qreal(0.5));
2461 const int h = int(rect.height() + qreal(0.5));
2462
2463 return QRect(x, y, w, h);
2464}
2465
2466static inline int fast_ceil_positive(const qreal &v)
2467{
2468 const int iv = int(v);
2469 if (v - iv == 0)
2470 return iv;
2471 else
2472 return iv + 1;
2473}
2474
2475static inline const QRect toAlignedRect_positive(const QRectF &rect)
2476{
2477 const int xmin = int(rect.x());
2478 const int xmax = int(fast_ceil_positive(rect.right()));
2479 const int ymin = int(rect.y());
2480 const int ymax = int(fast_ceil_positive(rect.bottom()));
2481 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2482}
2483
2484/*!
2485 \internal
2486*/
2487void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2488{
2489#ifdef QT_DEBUG_DRAW
2490 qDebug() << " - QRasterPaintEngine::drawImage(), p=" << p << " image=" << img.size() << "depth=" << img.depth();
2491#endif
2492
2493 Q_D(QRasterPaintEngine);
2494 QRasterPaintEngineState *s = state();
2495
2496 if (s->matrix.type() > QTransform::TxTranslate) {
2497 drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2498 img,
2499 QRectF(0, 0, img.width(), img.height()));
2500 } else {
2501
2502 const QClipData *clip = d->clip();
2503 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2504
2505 if (s->flags.fast_images) {
2506 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2507 if (func) {
2508 if (!clip) {
2509 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2510 return;
2511 } else if (clip->hasRectClip) {
2512 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2513 return;
2514 }
2515 }
2516 }
2517
2518
2519
2520 d->image_filler.clip = clip;
2521 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2522 if (!d->image_filler.blend)
2523 return;
2524 d->image_filler.dx = -pt.x();
2525 d->image_filler.dy = -pt.y();
2526 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2527
2528 fillRect_normalized(rr, &d->image_filler, d);
2529 }
2530
2531}
2532
2533QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2534{
2535 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2536}
2537
2538/*!
2539 \reimp
2540*/
2541void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2542 Qt::ImageConversionFlags)
2543{
2544#ifdef QT_DEBUG_DRAW
2545 qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2546#endif
2547
2548 if (r.isEmpty())
2549 return;
2550
2551 Q_D(QRasterPaintEngine);
2552 QRasterPaintEngineState *s = state();
2553 int sr_l = qFloor(sr.left());
2554 int sr_r = qCeil(sr.right()) - 1;
2555 int sr_t = qFloor(sr.top());
2556 int sr_b = qCeil(sr.bottom()) - 1;
2557
2558 if (!s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2559 // as fillRect will apply the aliased coordinate delta we need to
2560 // subtract it here as we don't use it for image drawing
2561 QTransform old = s->matrix;
2562 s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2563
2564 // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2565 QRgb color = img.pixel(sr_l, sr_t);
2566 switch (img.format()) {
2567 case QImage::Format_ARGB32_Premultiplied:
2568 case QImage::Format_ARGB8565_Premultiplied:
2569 case QImage::Format_ARGB6666_Premultiplied:
2570 case QImage::Format_ARGB8555_Premultiplied:
2571 case QImage::Format_ARGB4444_Premultiplied:
2572 // Combine premultiplied color with the opacity set on the painter.
2573 d->solid_color_filler.solid.color =
2574 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2575 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2576 break;
2577 default:
2578 d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2579 break;
2580 }
2581
2582 if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2583 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2584 return;
2585 }
2586
2587 d->solid_color_filler.clip = d->clip();
2588 d->solid_color_filler.adjustSpanMethods();
2589 fillRect(r, &d->solid_color_filler);
2590
2591 s->matrix = old;
2592 return;
2593 }
2594
2595 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2596
2597 const QClipData *clip = d->clip();
2598
2599 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2600
2601 if (s->flags.fast_images) {
2602 if (s->matrix.type() > QTransform::TxScale) {
2603 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2604 if (func && (!clip || clip->hasRectClip)) {
2605 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2606 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2607 s->matrix, s->intOpacity);
2608 return;
2609 }
2610 } else {
2611 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2612 if (func && (!clip || clip->hasRectClip)) {
2613 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2614 img.bits(), img.bytesPerLine(),
2615 qt_mapRect_non_normalizing(r, s->matrix), sr,
2616 !clip ? d->deviceRect : clip->clipRect,
2617 s->intOpacity);
2618 return;
2619 }
2620 }
2621 }
2622
2623 QTransform copy = s->matrix;
2624 copy.translate(r.x(), r.y());
2625 if (stretch_sr)
2626 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2627 copy.translate(-sr.x(), -sr.y());
2628
2629 d->image_filler_xform.clip = clip;
2630 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2631 if (!d->image_filler_xform.blend)
2632 return;
2633 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2634
2635 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2636 QRectF rr = s->matrix.mapRect(r);
2637
2638 const int x1 = qRound(rr.x());
2639 const int y1 = qRound(rr.y());
2640 const int x2 = qRound(rr.right());
2641 const int y2 = qRound(rr.bottom());
2642
2643 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2644 return;
2645 }
2646
2647#ifdef QT_FAST_SPANS
2648 ensureState();
2649 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2650 d->initializeRasterizer(&d->image_filler_xform);
2651 d->rasterizer->setAntialiased(s->flags.antialiased);
2652
2653 const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2654
2655 const QRectF &rect = r.normalized();
2656 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2657 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2658
2659 if (s->flags.tx_noshear)
2660 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2661 else
2662 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2663 return;
2664 }
2665#endif
2666 const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2667 QPainterPath path;
2668 path.addRect(r);
2669 QTransform m = s->matrix;
2670 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2671 m.m21(), m.m22(), m.m23(),
2672 m.m31() - offs, m.m32() - offs, m.m33());
2673 fillPath(path, &d->image_filler_xform);
2674 s->matrix = m;
2675 } else {
2676
2677 if (s->flags.fast_images) {
2678 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2679 if (func) {
2680 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2681 if (!clip) {
2682 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2683 return;
2684 } else if (clip->hasRectClip) {
2685 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2686 return;
2687 }
2688 }
2689 }
2690
2691 d->image_filler.clip = clip;
2692 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2693 if (!d->image_filler.blend)
2694 return;
2695 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2696 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2697
2698 QRectF rr = r;
2699 rr.translate(s->matrix.dx(), s->matrix.dy());
2700
2701 const int x1 = qRound(rr.x());
2702 const int y1 = qRound(rr.y());
2703 const int x2 = qRound(rr.right());
2704 const int y2 = qRound(rr.bottom());
2705
2706 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2707 }
2708}
2709
2710/*!
2711 \reimp
2712*/
2713void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2714{
2715#ifdef QT_DEBUG_DRAW
2716 qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2717#endif
2718 Q_D(QRasterPaintEngine);
2719 QRasterPaintEngineState *s = state();
2720
2721 QImage image;
2722
2723 if (pixmap.data->classId() == QPixmapData::RasterClass) {
2724 image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2725 } else {
2726 image = pixmap.toImage();
2727 }
2728
2729 if (image.depth() == 1)
2730 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2731
2732 if (s->matrix.type() > QTransform::TxTranslate) {
2733 QTransform copy = s->matrix;
2734 copy.translate(r.x(), r.y());
2735 copy.translate(-sr.x(), -sr.y());
2736 d->image_filler_xform.clip = d->clip();
2737 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2738 if (!d->image_filler_xform.blend)
2739 return;
2740 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2741
2742#ifdef QT_FAST_SPANS
2743 ensureState();
2744 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2745 d->initializeRasterizer(&d->image_filler_xform);
2746 d->rasterizer->setAntialiased(s->flags.antialiased);
2747
2748 const QRectF &rect = r.normalized();
2749 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2750 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2751 if (s->flags.tx_noshear)
2752 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2753 else
2754 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2755 return;
2756 }
2757#endif
2758 QPainterPath path;
2759 path.addRect(r);
2760 fillPath(path, &d->image_filler_xform);
2761 } else {
2762 d->image_filler.clip = d->clip();
2763
2764 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2765 if (!d->image_filler.blend)
2766 return;
2767 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2768 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2769
2770 QRectF rr = r;
2771 rr.translate(s->matrix.dx(), s->matrix.dy());
2772 fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2773 }
2774}
2775
2776
2777//QWS hack
2778static inline bool monoVal(const uchar* s, int x)
2779{
2780 return (s[x>>3] << (x&7)) & 0x80;
2781}
2782
2783/*!
2784 \internal
2785*/
2786void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2787{
2788 Q_D(QRasterPaintEngine);
2789 QRasterPaintEngineState *s = state();
2790
2791 if (!s->penData.blend)
2792 return;
2793
2794 QRasterBuffer *rb = d->rasterBuffer.data();
2795
2796 const QRect rect(rx, ry, w, h);
2797 const QClipData *clip = d->clip();
2798 bool unclipped = false;
2799 if (clip) {
2800 // inlined QRect::intersects
2801 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2802 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2803
2804 if (clip->hasRectClip) {
2805 unclipped = rx > clip->xmin
2806 && rx + w < clip->xmax
2807 && ry > clip->ymin
2808 && ry + h < clip->ymax;
2809 }
2810
2811 if (!intersects)
2812 return;
2813 } else {
2814 // inlined QRect::intersects
2815 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2816 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2817 if (!intersects)
2818 return;
2819
2820 // inlined QRect::contains
2821 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2822 && rect.top() >= 0 && rect.bottom() < rb->height();
2823
2824 unclipped = contains && d->isUnclipped_normalized(rect);
2825 }
2826
2827 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2828 const uchar * scanline = static_cast<const uchar *>(src);
2829
2830 if (s->flags.fast_text) {
2831 if (unclipped) {
2832 if (depth == 1) {
2833 if (s->penData.bitmapBlit) {
2834 s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2835 scanline, w, h, bpl);
2836 return;
2837 }
2838 } else if (depth == 8) {
2839 if (s->penData.alphamapBlit) {
2840 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2841 scanline, w, h, bpl, 0);
2842 return;
2843 }
2844 } else if (depth == 32) {
2845 // (A)RGB Alpha mask where the alpha component is not used.
2846 if (s->penData.alphaRGBBlit) {
2847 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2848 (const uint *) scanline, w, h, bpl / 4, 0);
2849 return;
2850 }
2851 }
2852 } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2853 // (A)RGB Alpha mask where the alpha component is not used.
2854 if (!clip) {
2855 int nx = qMax(0, rx);
2856 int ny = qMax(0, ry);
2857
2858 // Move scanline pointer to compensate for moved x and y
2859 int xdiff = nx - rx;
2860 int ydiff = ny - ry;
2861 scanline += ydiff * bpl;
2862 scanline += xdiff * (depth == 32 ? 4 : 1);
2863
2864 w -= xdiff;
2865 h -= ydiff;
2866
2867 if (nx + w > d->rasterBuffer->width())
2868 w = d->rasterBuffer->width() - nx;
2869 if (ny + h > d->rasterBuffer->height())
2870 h = d->rasterBuffer->height() - ny;
2871
2872 rx = nx;
2873 ry = ny;
2874 }
2875 if (depth == 8 && s->penData.alphamapBlit) {
2876 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2877 scanline, w, h, bpl, clip);
2878 } else if (depth == 32 && s->penData.alphaRGBBlit) {
2879 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2880 (const uint *) scanline, w, h, bpl / 4, clip);
2881 }
2882 return;
2883 }
2884 }
2885
2886 int x0 = 0;
2887 if (rx < 0) {
2888 x0 = -rx;
2889 w -= x0;
2890 }
2891
2892 int y0 = 0;
2893 if (ry < 0) {
2894 y0 = -ry;
2895 scanline += bpl * y0;
2896 h -= y0;
2897 }
2898
2899 w = qMin(w, rb->width() - qMax(0, rx));
2900 h = qMin(h, rb->height() - qMax(0, ry));
2901
2902 if (w <= 0 || h <= 0)
2903 return;
2904
2905 const int NSPANS = 256;
2906 QSpan spans[NSPANS];
2907 int current = 0;
2908
2909 const int x1 = x0 + w;
2910 const int y1 = y0 + h;
2911
2912 if (depth == 1) {
2913 for (int y = y0; y < y1; ++y) {
2914 for (int x = x0; x < x1; ) {
2915 if (!monoVal(scanline, x)) {
2916 ++x;
2917 continue;
2918 }
2919
2920 if (current == NSPANS) {
2921 blend(current, spans, &s->penData);
2922 current = 0;
2923 }
2924 spans[current].x = x + rx;
2925 spans[current].y = y + ry;
2926 spans[current].coverage = 255;
2927 int len = 1;
2928 ++x;
2929 // extend span until we find a different one.
2930 while (x < x1 && monoVal(scanline, x)) {
2931 ++x;
2932 ++len;
2933 }
2934 spans[current].len = len;
2935 ++current;
2936 }
2937 scanline += bpl;
2938 }
2939 } else if (depth == 8) {
2940 for (int y = y0; y < y1; ++y) {
2941 for (int x = x0; x < x1; ) {
2942 // Skip those with 0 coverage
2943 if (scanline[x] == 0) {
2944 ++x;
2945 continue;
2946 }
2947
2948 if (current == NSPANS) {
2949 blend(current, spans, &s->penData);
2950 current = 0;
2951 }
2952 int coverage = scanline[x];
2953 spans[current].x = x + rx;
2954 spans[current].y = y + ry;
2955 spans[current].coverage = coverage;
2956 int len = 1;
2957 ++x;
2958
2959 // extend span until we find a different one.
2960 while (x < x1 && scanline[x] == coverage) {
2961 ++x;
2962 ++len;
2963 }
2964 spans[current].len = len;
2965 ++current;
2966 }
2967 scanline += bpl;
2968 }
2969 } else { // 32-bit alpha...
2970 uint *sl = (uint *) src;
2971 for (int y = y0; y < y1; ++y) {
2972 for (int x = x0; x < x1; ) {
2973 // Skip those with 0 coverage
2974 if ((sl[x] & 0x00ffffff) == 0) {
2975 ++x;
2976 continue;
2977 }
2978
2979 if (current == NSPANS) {
2980 blend(current, spans, &s->penData);
2981 current = 0;
2982 }
2983 uint rgbCoverage = sl[x];
2984 int coverage = qGreen(rgbCoverage);
2985 spans[current].x = x + rx;
2986 spans[current].y = y + ry;
2987 spans[current].coverage = coverage;
2988 int len = 1;
2989 ++x;
2990
2991 // extend span until we find a different one.
2992 while (x < x1 && sl[x] == rgbCoverage) {
2993 ++x;
2994 ++len;
2995 }
2996 spans[current].len = len;
2997 ++current;
2998 }
2999 sl += bpl / sizeof(uint);
3000 }
3001 }
3002// qDebug() << "alphaPenBlt: num spans=" << current
3003// << "span:" << spans->x << spans->y << spans->len << spans->coverage;
3004 // Call span func for current set of spans.
3005 if (current != 0)
3006 blend(current, spans, &s->penData);
3007}
3008
3009void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
3010{
3011 Q_D(QRasterPaintEngine);
3012 QRasterPaintEngineState *s = state();
3013
3014 QVarLengthArray<QFixedPoint> positions;
3015 QVarLengthArray<glyph_t> glyphs;
3016 QTransform matrix = s->matrix;
3017 matrix.translate(p.x(), p.y());
3018 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3019
3020 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType;
3021
3022 QImageTextureGlyphCache *cache =
3023 (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix);
3024 if (!cache) {
3025 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
3026 ti.fontEngine->setGlyphCache(0, cache);
3027 }
3028
3029 cache->populate(ti, glyphs, positions);
3030
3031 const QImage &image = cache->image();
3032 int bpl = image.bytesPerLine();
3033
3034 int depth = image.depth();
3035 int rightShift = 0;
3036 int leftShift = 0;
3037 if (depth == 32)
3038 leftShift = 2; // multiply by 4
3039 else if (depth == 1)
3040 rightShift = 3; // divide by 8
3041
3042 int margin = cache->glyphMargin();
3043
3044 const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
3045
3046 const uchar *bits = image.bits();
3047 for (int i=0; i<glyphs.size(); ++i) {
3048 const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
3049 int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
3050 int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
3051
3052// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
3053// c.x, c.y,
3054// c.w, c.h,
3055// c.baseLineX, c.baseLineY,
3056// glyphs[i],
3057// x, y,
3058// positions[i].x.toInt(), positions[i].y.toInt());
3059
3060 alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
3061 }
3062
3063 return;
3064}
3065
3066#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
3067void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
3068{
3069 Q_D(QRasterPaintEngine);
3070 QRasterPaintEngineState *s = state();
3071
3072 QFontEngine *fontEngine = ti.fontEngine;
3073 if (fontEngine->type() != QFontEngine::S60FontEngine) {
3074 QPaintEngineEx::drawTextItem(p, ti);
3075 return;
3076 }
3077
3078 QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
3079
3080 QVarLengthArray<QFixedPoint> positions;
3081 QVarLengthArray<glyph_t> glyphs;
3082 QTransform matrix = s->matrix;
3083 matrix.translate(p.x(), p.y());
3084 if (matrix.type() == QTransform::TxScale)
3085 fe->setFontScale(matrix.m11());
3086 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3087
3088 const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
3089
3090 for (int i=0; i<glyphs.size(); ++i) {
3091 TOpenFontCharMetrics tmetrics;
3092 const TUint8 *glyphBitmapBytes;
3093 TSize glyphBitmapSize;
3094 fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
3095 const glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]);
3096 const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
3097 const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
3098
3099 alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
3100 }
3101
3102 if (matrix.type() == QTransform::TxScale)
3103 fe->setFontScale(1.0);
3104
3105 return;
3106}
3107#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
3108
3109/*!
3110 * Returns true if the rectangle is completly within the current clip
3111 * state of the paint engine.
3112 */
3113bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
3114{
3115 const QClipData *cl = clip();
3116 if (!cl) {
3117 // inline contains() for performance (we know the rects are normalized)
3118 const QRect &r1 = deviceRect;
3119 return (r.left() >= r1.left() && r.right() <= r1.right()
3120 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3121 }
3122
3123
3124 if (cl->hasRectClip) {
3125 // currently all painting functions clips to deviceRect internally
3126 if (cl->clipRect == deviceRect)
3127 return true;
3128
3129 // inline contains() for performance (we know the rects are normalized)
3130 const QRect &r1 = cl->clipRect;
3131 return (r.left() >= r1.left() && r.right() <= r1.right()
3132 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3133 } else {
3134 return qt_region_strictContains(cl->clipRegion, r);
3135 }
3136}
3137
3138bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
3139 int penWidth) const
3140{
3141 Q_Q(const QRasterPaintEngine);
3142 const QRasterPaintEngineState *s = q->state();
3143 const QClipData *cl = clip();
3144 if (!cl) {
3145 QRect r = rect.normalized();
3146 // inline contains() for performance (we know the rects are normalized)
3147 const QRect &r1 = deviceRect;
3148 return (r.left() >= r1.left() && r.right() <= r1.right()
3149 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3150 }
3151
3152
3153 // currently all painting functions that call this function clip to deviceRect internally
3154 if (cl->hasRectClip && cl->clipRect == deviceRect)
3155 return true;
3156
3157 if (s->flags.antialiased)
3158 ++penWidth;
3159
3160 QRect r = rect.normalized();
3161 if (penWidth > 0) {
3162 r.setX(r.x() - penWidth);
3163 r.setY(r.y() - penWidth);
3164 r.setWidth(r.width() + 2 * penWidth);
3165 r.setHeight(r.height() + 2 * penWidth);
3166 }
3167
3168 if (cl->hasRectClip) {
3169 // inline contains() for performance (we know the rects are normalized)
3170 const QRect &r1 = cl->clipRect;
3171 return (r.left() >= r1.left() && r.right() <= r1.right()
3172 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3173 } else {
3174 return qt_region_strictContains(cl->clipRegion, r);
3175 }
3176}
3177
3178inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3179 int penWidth) const
3180{
3181 return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3182}
3183
3184inline ProcessSpans
3185QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3186 const QSpanData *data) const
3187{
3188 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3189}
3190
3191inline ProcessSpans
3192QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3193 const QSpanData *data) const
3194{
3195 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3196}
3197
3198inline ProcessSpans
3199QRasterPaintEnginePrivate::getPenFunc(const QRect &rect,
3200 const QSpanData *data) const
3201{
3202 Q_Q(const QRasterPaintEngine);
3203 const QRasterPaintEngineState *s = q->state();
3204
3205 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3206 return data->blend;
3207 const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->pen.widthF());
3208 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3209}
3210
3211inline ProcessSpans
3212QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
3213 const QSpanData *data) const
3214{
3215 Q_Q(const QRasterPaintEngine);
3216 const QRasterPaintEngineState *s = q->state();
3217
3218 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3219 return data->blend;
3220 const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
3221 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3222}
3223
3224/*!
3225 \reimp
3226*/
3227void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3228{
3229 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3230 QRasterPaintEngineState *s = state();
3231
3232#ifdef QT_DEBUG_DRAW
3233 Q_D(QRasterPaintEngine);
3234 fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3235 p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3236 d->glyphCacheType);
3237#endif
3238
3239 ensurePen();
3240 ensureState();
3241
3242#if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3243
3244 bool drawCached = true;
3245
3246 if (s->matrix.type() >= QTransform::TxProject)
3247 drawCached = false;
3248
3249 // don't try to cache huge fonts
3250 const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
3251 if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64)
3252 drawCached = false;
3253
3254 // ### Remove the TestFontEngine and Box engine crap, in these
3255 // ### cases we should delegate painting to the font engine
3256 // ### directly...
3257
3258#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3259 QFontEngine::Type fontEngineType = ti.fontEngine->type();
3260 // qDebug() << "type" << fontEngineType << s->matrix.type();
3261 if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
3262 || (s->matrix.type() <= QTransform::TxTranslate
3263 && (fontEngineType == QFontEngine::TestFontEngine
3264 || fontEngineType == QFontEngine::Box))) {
3265 drawCached = false;
3266 }
3267#else
3268 if (s->matrix.type() > QTransform::TxTranslate)
3269 drawCached = false;
3270#endif
3271 if (drawCached) {
3272 drawCachedGlyphs(p, ti);
3273 return;
3274 }
3275
3276#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3277 if (s->matrix.type() <= QTransform::TxTranslate
3278 || (s->matrix.type() == QTransform::TxScale
3279 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3280 drawGlyphsS60(p, ti);
3281 return;
3282 }
3283#else // Q_WS_WIN || Q_WS_MAC
3284
3285 QFontEngine *fontEngine = ti.fontEngine;
3286
3287#if defined(Q_WS_QWS)
3288 if (fontEngine->type() == QFontEngine::Box) {
3289 fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3290 return;
3291 }
3292
3293 if (s->matrix.type() < QTransform::TxScale
3294 && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3295 || (fontEngine->type() == QFontEngine::Proxy
3296 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3297 )) {
3298 fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3299 return;
3300 }
3301#endif // Q_WS_QWS
3302
3303#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) || defined(Q_WS_PM)) && !defined(QT_NO_FREETYPE)
3304
3305#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3306 if (fontEngine->type() == QFontEngine::QPF2) {
3307 QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3308 if (renderingEngine)
3309 fontEngine = renderingEngine;
3310 }
3311#endif
3312
3313 if (fontEngine->type() != QFontEngine::Freetype) {
3314 QPaintEngineEx::drawTextItem(p, ti);
3315 return;
3316 }
3317
3318 QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3319
3320 QTransform matrix = s->matrix;
3321 matrix.translate(p.x(), p.y());
3322
3323 QVarLengthArray<QFixedPoint> positions;
3324 QVarLengthArray<glyph_t> glyphs;
3325 fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3326 if (glyphs.size() == 0)
3327 return;
3328
3329 // only use subpixel antialiasing when drawing to widgets
3330 QFontEngineFT::GlyphFormat neededFormat =
3331 painter()->device()->devType() == QInternal::Widget
3332 ? fe->defaultGlyphFormat()
3333 : QFontEngineFT::Format_A8;
3334
3335 if (d_func()->mono_surface
3336 || fe->isBitmapFont() // alphaPenBlt can handle mono, too
3337 )
3338 neededFormat = QFontEngineFT::Format_Mono;
3339
3340 if (neededFormat == QFontEngineFT::Format_None)
3341 neededFormat = QFontEngineFT::Format_A8;
3342
3343 QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
3344 if (s->matrix.type() >= QTransform::TxScale) {
3345 if (s->matrix.isAffine())
3346 gset = fe->loadTransformedGlyphSet(s->matrix);
3347 else
3348 gset = 0;
3349
3350 }
3351
3352 if (!gset || gset->outline_drawing
3353 || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), neededFormat))
3354 {
3355 QPaintEngine::drawTextItem(p, ti);
3356 return;
3357 }
3358
3359 QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
3360 FT_Face lockedFace = 0;
3361
3362 int depth;
3363 switch (neededFormat) {
3364 case QFontEngineFT::Format_Mono:
3365 depth = 1;
3366 break;
3367 case QFontEngineFT::Format_A8:
3368 depth = 8;
3369 break;
3370 case QFontEngineFT::Format_A32:
3371 depth = 32;
3372 break;
3373 default:
3374 Q_ASSERT(false);
3375 depth = 0;
3376 };
3377
3378 for(int i = 0; i < glyphs.size(); i++) {
3379 QFontEngineFT::Glyph *glyph = gset->glyph_data.value(glyphs[i]);
3380
3381 if (!glyph || glyph->format != neededFormat) {
3382 if (!lockedFace)
3383 lockedFace = fe->lockFace();
3384 glyph = fe->loadGlyph(gset, glyphs[i], neededFormat);
3385 }
3386
3387 if (!glyph || !glyph->data)
3388 continue;
3389
3390 int pitch;
3391 switch (neededFormat) {
3392 case QFontEngineFT::Format_Mono:
3393 pitch = ((glyph->width + 31) & ~31) >> 3;
3394 break;
3395 case QFontEngineFT::Format_A8:
3396 pitch = (glyph->width + 3) & ~3;
3397 break;
3398 case QFontEngineFT::Format_A32:
3399 pitch = glyph->width * 4;
3400 break;
3401 default:
3402 Q_ASSERT(false);
3403 pitch = 0;
3404 };
3405
3406 alphaPenBlt(glyph->data, pitch, depth,
3407 qFloor(positions[i].x + offs) + glyph->x,
3408 qFloor(positions[i].y + offs) - glyph->y,
3409 glyph->width, glyph->height);
3410 }
3411 if (lockedFace)
3412 fe->unlockFace();
3413 return;
3414
3415#endif
3416#endif
3417
3418 QPaintEngineEx::drawTextItem(p, ti);
3419}
3420
3421/*!
3422 \reimp
3423*/
3424void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3425{
3426 Q_D(QRasterPaintEngine);
3427 QRasterPaintEngineState *s = state();
3428
3429 ensurePen();
3430 qreal pw = s->lastPen.widthF();
3431 if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
3432 QPaintEngineEx::drawPoints(points, pointCount);
3433
3434 } else {
3435 if (!s->penData.blend)
3436 return;
3437
3438 QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
3439 QT_FT_Span span = { 0, 1, 0, 255 };
3440 const QPointF *end = points + pointCount;
3441 qreal trans_x, trans_y;
3442 int x, y;
3443 int left = d->deviceRect.x();
3444 int right = left + d->deviceRect.width();
3445 int top = d->deviceRect.y();
3446 int bottom = top + d->deviceRect.height();
3447 int count = 0;
3448 while (points < end) {
3449 s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
3450 x = qFloor(trans_x);
3451 y = qFloor(trans_y);
3452 if (x >= left && x < right && y >= top && y < bottom) {
3453 if (count > 0) {
3454 const QT_FT_Span &last = array[count - 1];
3455 // spans must be sorted on y (primary) and x (secondary)
3456 if (y < last.y || (y == last.y && x < last.x)) {
3457 s->penData.blend(count, array.constData(), &s->penData);
3458 count = 0;
3459 }
3460 }
3461
3462 span.x = x;
3463 span.y = y;
3464 array[count++] = span;
3465 }
3466 ++points;
3467 }
3468
3469 if (count > 0)
3470 s->penData.blend(count, array.constData(), &s->penData);
3471 }
3472}
3473
3474
3475void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3476{
3477 Q_D(QRasterPaintEngine);
3478 QRasterPaintEngineState *s = state();
3479
3480 ensurePen();
3481 double pw = s->lastPen.widthF();
3482 if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
3483 QPaintEngineEx::drawPoints(points, pointCount);
3484
3485 } else {
3486 if (!s->penData.blend)
3487 return;
3488
3489 QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
3490 QT_FT_Span span = { 0, 1, 0, 255 };
3491 const QPoint *end = points + pointCount;
3492 qreal trans_x, trans_y;
3493 int x, y;
3494 int left = d->deviceRect.x();
3495 int right = left + d->deviceRect.width();
3496 int top = d->deviceRect.y();
3497 int bottom = top + d->deviceRect.height();
3498 int count = 0;
3499 while (points < end) {
3500 s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
3501 x = qFloor(trans_x);
3502 y = qFloor(trans_y);
3503 if (x >= left && x < right && y >= top && y < bottom) {
3504 if (count > 0) {
3505 const QT_FT_Span &last = array[count - 1];
3506 // spans must be sorted on y (primary) and x (secondary)
3507 if (y < last.y || (y == last.y && x < last.x)) {
3508 s->penData.blend(count, array.constData(), &s->penData);
3509 count = 0;
3510 }
3511 }
3512
3513 span.x = x;
3514 span.y = y;
3515 array[count++] = span;
3516 }
3517 ++points;
3518 }
3519
3520 if (count > 0)
3521 s->penData.blend(count, array.constData(), &s->penData);
3522 }
3523}
3524
3525/*!
3526 \reimp
3527*/
3528void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3529{
3530#ifdef QT_DEBUG_DRAW
3531 qDebug() << " - QRasterPaintEngine::drawLine()";
3532#endif
3533 Q_D(QRasterPaintEngine);
3534 QRasterPaintEngineState *s = state();
3535
3536 ensurePen();
3537 if (s->flags.fast_pen) {
3538 QIntRect bounds; bounds.set(d->deviceRect);
3539 LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
3540 ? LineDrawNormal
3541 : LineDrawIncludeLastPixel;
3542
3543 int m11 = int(s->matrix.m11());
3544 int m22 = int(s->matrix.m22());
3545 int dx = qFloor(s->matrix.dx() + aliasedCoordinateDelta);
3546 int dy = qFloor(s->matrix.dy() + aliasedCoordinateDelta);
3547 for (int i=0; i<lineCount; ++i) {
3548 int dashOffset = int(s->lastPen.dashOffset());
3549 if (s->flags.int_xform) {
3550 const QLine &l = lines[i];
3551 int x1 = l.x1() * m11 + dx;
3552 int y1 = l.y1() * m22 + dy;
3553 int x2 = l.x2() * m11 + dx;
3554 int y2 = l.y2() * m22 + dy;
3555
3556 const QRect brect(QPoint(x1, y1), QPoint(x2, y2));
3557 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
3558 if (qpen_style(s->lastPen) == Qt::SolidLine)
3559 drawLine_midpoint_i(x1, y1, x2, y2,
3560 penBlend, &s->penData, mode, bounds);
3561 else
3562 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
3563 &s->lastPen, penBlend,
3564 &s->penData, mode, bounds,
3565 &dashOffset);
3566 } else {
3567 QLineF line = lines[i] * s->matrix;
3568 const QRectF brect(QPointF(line.x1(), line.y1()),
3569 QPointF(line.x2(), line.y2()));
3570 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
3571 if (qpen_style(s->lastPen) == Qt::SolidLine)
3572 drawLine_midpoint_i(int(line.x1()), int(line.y1()),
3573 int(line.x2()), int(line.y2()),
3574 penBlend, &s->penData, mode, bounds);
3575 else
3576 drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
3577 int(line.x2()), int(line.y2()),
3578 &s->lastPen, penBlend,
3579 &s->penData, mode, bounds,
3580 &dashOffset);
3581 }
3582 }
3583 } else if (s->penData.blend) {
3584 QPaintEngineEx::drawLines(lines, lineCount);
3585 }
3586}
3587
3588void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3589 qreal width,
3590 int *dashIndex,
3591 qreal *dashOffset,
3592 bool *inDash)
3593{
3594 Q_Q(QRasterPaintEngine);
3595 QRasterPaintEngineState *s = q->state();
3596
3597 const QPen &pen = s->lastPen;
3598 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3599 const QVector<qreal> pattern = pen.dashPattern();
3600
3601 qreal length = line.length();
3602 Q_ASSERT(length > 0);
3603 while (length > 0) {
3604 const bool rasterize = *inDash;
3605 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3606 QLineF l = line;
3607
3608 if (dash >= length) {
3609 dash = length;
3610 *dashOffset += dash / width;
3611 length = 0;
3612 } else {
3613 *dashOffset = 0;
3614 *inDash = !(*inDash);
3615 *dashIndex = (*dashIndex + 1) % pattern.size();
3616 length -= dash;
3617 l.setLength(dash);
3618 line.setP1(l.p2());
3619 }
3620
3621 if (rasterize && dash != 0)
3622 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3623 }
3624}
3625
3626/*!
3627 \reimp
3628*/
3629void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3630{
3631#ifdef QT_DEBUG_DRAW
3632 qDebug() << " - QRasterPaintEngine::drawLine()";
3633#endif
3634 Q_D(QRasterPaintEngine);
3635 QRasterPaintEngineState *s = state();
3636
3637 ensurePen();
3638 if (!s->penData.blend)
3639 return;
3640 if (s->flags.fast_pen) {
3641 QIntRect bounds;
3642 bounds.set(d->deviceRect);
3643 LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
3644 ? LineDrawNormal
3645 : LineDrawIncludeLastPixel;
3646
3647 for (int i=0; i<lineCount; ++i) {
3648 int dashOffset = int(s->lastPen.dashOffset());
3649 QLineF line = (lines[i] * s->matrix).translated(aliasedCoordinateDelta, aliasedCoordinateDelta);
3650 const QRectF brect(QPointF(line.x1(), line.y1()),
3651 QPointF(line.x2(), line.y2()));
3652 ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
3653 if (qpen_style(s->lastPen) == Qt::SolidLine)
3654 drawLine_midpoint_i(int(line.x1()), int(line.y1()),
3655 int(line.x2()), int(line.y2()),
3656 penBlend, &s->penData, mode, bounds);
3657 else
3658 drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
3659 int(line.x2()), int(line.y2()),
3660 &s->lastPen,
3661 penBlend, &s->penData, mode,
3662 bounds, &dashOffset);
3663 }
3664 } else {
3665 QPaintEngineEx::drawLines(lines, lineCount);
3666 }
3667}
3668
3669
3670/*!
3671 \reimp
3672*/
3673void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3674{
3675 Q_D(QRasterPaintEngine);
3676 QRasterPaintEngineState *s = state();
3677
3678 ensurePen();
3679 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3680 || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased))
3681 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3682#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
3683 && qMax(rect.width(), rect.height()) < 128 // integer math breakdown
3684#endif
3685 && s->matrix.type() <= QTransform::TxScale) // no shear
3686 {
3687 ensureBrush();
3688 const QRectF r = s->matrix.mapRect(rect);
3689 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3690 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3691 const QRect brect = QRect(int(r.x()), int(r.y()),
3692 int_dim(r.x(), r.width()),
3693 int_dim(r.y(), r.height()));
3694 if (brect == r) {
3695 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3696 &s->penData, &s->brushData);
3697 return;
3698 }
3699 }
3700 QPaintEngineEx::drawEllipse(rect);
3701}
3702
3703/*!
3704 \internal
3705*/
3706#ifdef Q_WS_MAC
3707void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3708{
3709 Q_D(QRasterPaintEngine);
3710 d->cgContext = ctx;
3711}
3712
3713/*!
3714 \internal
3715*/
3716CGContextRef QRasterPaintEngine::getCGContext() const
3717{
3718 Q_D(const QRasterPaintEngine);
3719 return d->cgContext;
3720}
3721#endif
3722
3723#ifdef Q_WS_WIN
3724/*!
3725 \internal
3726*/
3727void QRasterPaintEngine::setDC(HDC hdc) {
3728 Q_D(QRasterPaintEngine);
3729 d->hdc = hdc;
3730}
3731
3732/*!
3733 \internal
3734*/
3735HDC QRasterPaintEngine::getDC() const
3736{
3737 Q_D(const QRasterPaintEngine);
3738 return d->hdc;
3739}
3740
3741/*!
3742 \internal
3743*/
3744void QRasterPaintEngine::releaseDC(HDC) const
3745{
3746}
3747
3748#endif
3749
3750/*!
3751 \internal
3752*/
3753QPoint QRasterPaintEngine::coordinateOffset() const
3754{
3755 return QPoint(0, 0);
3756}
3757
3758/*!
3759 Draws the given color \a spans with the specified \a color. The \a
3760 count parameter specifies the number of spans.
3761
3762 The default implementation does nothing; reimplement this function
3763 to draw the given color \a spans with the specified \a color. Note
3764 that this function \e must be reimplemented if the framebuffer is
3765 not memory-mapped.
3766
3767 \sa drawBufferSpan()
3768*/
3769#if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3770void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3771{
3772 Q_UNUSED(spans);
3773 Q_UNUSED(count);
3774 Q_UNUSED(color);
3775 qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3776 "a non memory-mapped device");
3777}
3778
3779/*!
3780 \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3781
3782 Draws the given \a buffer.
3783
3784 The default implementation does nothing; reimplement this function
3785 to draw a buffer that contains more than one color. Note that this
3786 function \e must be reimplemented if the framebuffer is not
3787 memory-mapped.
3788
3789 The \a size parameter specifies the total size of the given \a
3790 buffer, while the \a length parameter specifies the number of
3791 pixels to draw. The buffer's position is given by (\a x, \a
3792 y). The provided \a alpha value is added to each pixel in the
3793 buffer when drawing.
3794
3795 \sa drawColorSpans()
3796*/
3797void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3798 int x, int y, int length, uint const_alpha)
3799{
3800 Q_UNUSED(buffer);
3801 Q_UNUSED(bufsize);
3802 Q_UNUSED(x);
3803 Q_UNUSED(y);
3804 Q_UNUSED(length);
3805 Q_UNUSED(const_alpha);
3806 qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3807 "a non memory-mapped device");
3808}
3809#endif // Q_WS_QWS
3810
3811void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3812{
3813 Q_ASSERT(fg);
3814 if (!fg->blend)
3815 return;
3816 Q_D(QRasterPaintEngine);
3817
3818 Q_ASSERT(image.depth() == 1);
3819
3820 const int spanCount = 256;
3821 QT_FT_Span spans[spanCount];
3822 int n = 0;
3823
3824 // Boundaries
3825 int w = image.width();
3826 int h = image.height();
3827 int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3828 int ymin = qMax(qRound(pos.y()), 0);
3829 int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3830 int xmin = qMax(qRound(pos.x()), 0);
3831
3832 int x_offset = xmin - qRound(pos.x());
3833
3834 QImage::Format format = image.format();
3835 for (int y = ymin; y < ymax; ++y) {
3836 const uchar *src = image.scanLine(y - qRound(pos.y()));
3837 if (format == QImage::Format_MonoLSB) {
3838 for (int x = 0; x < xmax - xmin; ++x) {
3839 int src_x = x + x_offset;
3840 uchar pixel = src[src_x >> 3];
3841 if (!pixel) {
3842 x += 7 - (src_x%8);
3843 continue;
3844 }
3845 if (pixel & (0x1 << (src_x & 7))) {
3846 spans[n].x = xmin + x;
3847 spans[n].y = y;
3848 spans[n].coverage = 255;
3849 int len = 1;
3850 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3851 ++src_x;
3852 ++len;
3853 }
3854 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3855 x += len;
3856 ++n;
3857 if (n == spanCount) {
3858 fg->blend(n, spans, fg);
3859 n = 0;
3860 }
3861 }
3862 }
3863 } else {
3864 for (int x = 0; x < xmax - xmin; ++x) {
3865 int src_x = x + x_offset;
3866 uchar pixel = src[src_x >> 3];
3867 if (!pixel) {
3868 x += 7 - (src_x%8);
3869 continue;
3870 }
3871 if (pixel & (0x80 >> (x & 7))) {
3872 spans[n].x = xmin + x;
3873 spans[n].y = y;
3874 spans[n].coverage = 255;
3875 int len = 1;
3876 while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3877 ++src_x;
3878 ++len;
3879 }
3880 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3881 x += len;
3882 ++n;
3883 if (n == spanCount) {
3884 fg->blend(n, spans, fg);
3885 n = 0;
3886 }
3887 }
3888 }
3889 }
3890 }
3891 if (n) {
3892 fg->blend(n, spans, fg);
3893 n = 0;
3894 }
3895}
3896
3897/*!
3898 \enum QRasterPaintEngine::ClipType
3899 \internal
3900
3901 \value RectClip Indicates that the currently set clip is a single rectangle.
3902 \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3903*/
3904
3905/*!
3906 \internal
3907 Returns the type of the clip currently set.
3908*/
3909QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3910{
3911 Q_D(const QRasterPaintEngine);
3912
3913 const QClipData *clip = d->clip();
3914 if (!clip || clip->hasRectClip)
3915 return RectClip;
3916 else
3917 return ComplexClip;
3918}
3919
3920/*!
3921 \internal
3922 Returns the bounding rect of the currently set clip.
3923*/
3924QRect QRasterPaintEngine::clipBoundingRect() const
3925{
3926 Q_D(const QRasterPaintEngine);
3927
3928 const QClipData *clip = d->clip();
3929
3930 if (!clip)
3931 return d->deviceRect;
3932
3933 if (clip->hasRectClip)
3934 return clip->clipRect;
3935
3936 return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3937}
3938
3939static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3940{
3941 Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3942
3943 QVarLengthArray<short, 4096> buffer;
3944
3945 QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3946 QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3947 result->initialize();
3948
3949 for (int y = 0; y < c1->clipSpanHeight; ++y) {
3950 const QSpan *c1_spans = c1ClipLines[y].spans;
3951 int c1_count = c1ClipLines[y].count;
3952 const QSpan *c2_spans = c2ClipLines[y].spans;
3953 int c2_count = c2ClipLines[y].count;
3954
3955 if (c1_count == 0 && c2_count == 0)
3956 continue;
3957 if (c1_count == 0) {
3958 result->appendSpans(c2_spans, c2_count);
3959 continue;
3960 } else if (c2_count == 0) {
3961 result->appendSpans(c1_spans, c1_count);
3962 continue;
3963 }
3964
3965 // we need to merge the two
3966
3967 // find required length
3968 int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3969 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3970 buffer.resize(max);
3971 memset(buffer.data(), 0, buffer.size() * sizeof(short));
3972
3973 // Fill with old spans.
3974 for (int i = 0; i < c1_count; ++i) {
3975 const QSpan *cs = c1_spans + i;
3976 for (int j=cs->x; j<cs->x + cs->len; ++j)
3977 buffer[j] = cs->coverage;
3978 }
3979
3980 // Fill with new spans
3981 for (int i = 0; i < c2_count; ++i) {
3982 const QSpan *cs = c2_spans + i;
3983 for (int j = cs->x; j < cs->x + cs->len; ++j) {
3984 buffer[j] += cs->coverage;
3985 if (buffer[j] > 255)
3986 buffer[j] = 255;
3987 }
3988 }
3989
3990 int x = 0;
3991 while (x<max) {
3992
3993 // Skip to next span
3994 while (x < max && buffer[x] == 0) ++x;
3995 if (x >= max) break;
3996
3997 int sx = x;
3998 int coverage = buffer[x];
3999
4000 // Find length of span
4001 while (x < max && buffer[x] == coverage)
4002 ++x;
4003
4004 result->appendSpan(sx, x - sx, y, coverage);
4005 }
4006 }
4007}
4008
4009void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
4010{
4011 Q_Q(QRasterPaintEngine);
4012 QRasterPaintEngineState *s = q->state();
4013
4014 rasterizer->setAntialiased(s->flags.antialiased);
4015
4016 QRect clipRect(deviceRect);
4017 ProcessSpans blend;
4018 // ### get from optimized rectbased QClipData
4019
4020 const QClipData *c = clip();
4021 if (c) {
4022 const QRect r(QPoint(c->xmin, c->ymin),
4023 QSize(c->xmax - c->xmin, c->ymax - c->ymin));
4024 clipRect = clipRect.intersected(r);
4025 blend = data->blend;
4026 } else {
4027 blend = data->unclipped_blend;
4028 }
4029
4030 rasterizer->setClipRect(clipRect);
4031 rasterizer->initialize(blend, data);
4032}
4033
4034void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
4035 ProcessSpans callback,
4036 QSpanData *spanData, QRasterBuffer *rasterBuffer)
4037{
4038 if (!callback || !outline)
4039 return;
4040
4041 Q_Q(QRasterPaintEngine);
4042 QRasterPaintEngineState *s = q->state();
4043
4044 if (!s->flags.antialiased) {
4045 initializeRasterizer(spanData);
4046
4047 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
4048 ? Qt::WindingFill
4049 : Qt::OddEvenFill;
4050
4051 rasterizer->rasterize(outline, fillRule);
4052 return;
4053 }
4054
4055 rasterize(outline, callback, (void *)spanData, rasterBuffer);
4056}
4057
4058void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
4059 ProcessSpans callback,
4060 void *userData, QRasterBuffer *)
4061{
4062 if (!callback || !outline)
4063 return;
4064
4065 Q_Q(QRasterPaintEngine);
4066 QRasterPaintEngineState *s = q->state();
4067
4068 if (!s->flags.antialiased) {
4069 rasterizer->setAntialiased(s->flags.antialiased);
4070 rasterizer->setClipRect(deviceRect);
4071 rasterizer->initialize(callback, userData);
4072
4073 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
4074 ? Qt::WindingFill
4075 : Qt::OddEvenFill;
4076
4077 rasterizer->rasterize(outline, fillRule);
4078 return;
4079 }
4080
4081 void *data = userData;
4082
4083 QT_FT_BBox clip_box = { deviceRect.x(),
4084 deviceRect.y(),
4085 deviceRect.x() + deviceRect.width(),
4086 deviceRect.y() + deviceRect.height() };
4087
4088 QT_FT_Raster_Params rasterParams;
4089 rasterParams.target = 0;
4090 rasterParams.source = outline;
4091 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
4092 rasterParams.gray_spans = 0;
4093 rasterParams.black_spans = 0;
4094 rasterParams.bit_test = 0;
4095 rasterParams.bit_set = 0;
4096 rasterParams.user = data;
4097 rasterParams.clip_box = clip_box;
4098
4099 bool done = false;
4100 int error;
4101
4102 while (!done) {
4103
4104 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
4105 rasterParams.gray_spans = callback;
4106 error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
4107
4108 // Out of memory, reallocate some more and try again...
4109 if (error == -6) { // -6 is Result_err_OutOfMemory
4110 int new_size = rasterPoolSize * 2;
4111 if (new_size > 1024 * 1024) {
4112 qWarning("QPainter: Rasterization of primitive failed");
4113 return;
4114 }
4115
4116#if defined(Q_WS_WIN64)
4117 _aligned_free(rasterPoolBase);
4118#else
4119 free(rasterPoolBase);
4120#endif
4121
4122 rasterPoolSize = new_size;
4123 rasterPoolBase =
4124#if defined(Q_WS_WIN64)
4125 // We make use of setjmp and longjmp in qgrayraster.c which requires
4126 // 16-byte alignment, hence we hardcode this requirement here..
4127 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
4128#else
4129 (unsigned char *) malloc(rasterPoolSize);
4130#endif
4131 Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
4132
4133 qt_ft_grays_raster.raster_done(*grayRaster.data());
4134 qt_ft_grays_raster.raster_new(0, grayRaster.data());
4135 qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
4136 } else {
4137 done = true;
4138 }
4139 }
4140}
4141
4142void QRasterPaintEnginePrivate::recalculateFastImages()
4143{
4144 Q_Q(QRasterPaintEngine);
4145 QRasterPaintEngineState *s = q->state();
4146
4147 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
4148 && rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
4149 && s->matrix.type() <= QTransform::TxShear;
4150}
4151
4152
4153
4154QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
4155{
4156 Q_ASSERT(image.depth() == 1);
4157
4158 QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
4159 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
4160
4161 QRgb fg = PREMUL(color.rgba());
4162 QRgb bg = 0;
4163
4164 int height = sourceImage.height();
4165 int width = sourceImage.width();
4166 for (int y=0; y<height; ++y) {
4167 uchar *source = sourceImage.scanLine(y);
4168 QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
4169 if (!source || !target)
4170 QT_THROW(std::bad_alloc()); // we must have run out of memory
4171 for (int x=0; x < width; ++x)
4172 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
4173 }
4174 return dest;
4175}
4176
4177QRasterBuffer::~QRasterBuffer()
4178{
4179}
4180
4181void QRasterBuffer::init()
4182{
4183 compositionMode = QPainter::CompositionMode_SourceOver;
4184 monoDestinationWithClut = false;
4185 destColor0 = 0;
4186 destColor1 = 0;
4187}
4188
4189QImage::Format QRasterBuffer::prepare(QImage *image)
4190{
4191 m_buffer = (uchar *)image->bits();
4192 m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
4193 m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
4194 bytes_per_pixel = image->depth()/8;
4195 bytes_per_line = image->bytesPerLine();
4196
4197 format = image->format();
4198 drawHelper = qDrawHelper + format;
4199 if (image->depth() == 1 && image->colorTable().size() == 2) {
4200 monoDestinationWithClut = true;
4201 destColor0 = PREMUL(image->colorTable()[0]);
4202 destColor1 = PREMUL(image->colorTable()[1]);
4203 }
4204
4205 return format;
4206}
4207
4208void QRasterBuffer::resetBuffer(int val)
4209{
4210 memset(m_buffer, val, m_height*bytes_per_line);
4211}
4212
4213
4214#if defined(Q_WS_QWS)
4215void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
4216{
4217 m_buffer = reinterpret_cast<uchar*>(device->memory());
4218 m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
4219 m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
4220 bytes_per_pixel = device->depth() / 8;
4221 bytes_per_line = device->bytesPerLine();
4222 format = device->format();
4223#ifndef QT_NO_RASTERCALLBACKS
4224 if (!m_buffer)
4225 drawHelper = qDrawHelperCallback + format;
4226 else
4227#endif
4228 drawHelper = qDrawHelper + format;
4229}
4230
4231int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
4232{
4233 switch (m) {
4234 case PdmWidth:
4235 return widget->frameGeometry().width();
4236 case PdmHeight:
4237 return widget->frameGeometry().height();
4238 default:
4239 break;
4240 }
4241
4242 return qt_paint_device_metric(widget, m);
4243}
4244
4245int QCustomRasterPaintDevice::bytesPerLine() const
4246{
4247 return (width() * depth() + 7) / 8;
4248}
4249
4250#elif defined(Q_OS_SYMBIAN)
4251
4252void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
4253{
4254}
4255
4256#endif // Q_OS_SYMBIAN
4257
4258/*!
4259 \class QCustomRasterPaintDevice
4260 \preliminary
4261 \ingroup qws
4262 \since 4.2
4263
4264 \brief The QCustomRasterPaintDevice class is provided to activate
4265 hardware accelerated paint engines in Qt for Embedded Linux.
4266
4267 Note that this class is only available in \l{Qt for Embedded Linux}.
4268
4269 In \l{Qt for Embedded Linux}, painting is a pure software
4270 implementation. But starting with Qt 4.2, it is
4271 possible to add an accelerated graphics driver to take advantage
4272 of available hardware resources.
4273
4274 Hardware acceleration is accomplished by creating a custom screen
4275 driver, accelerating the copying from memory to the screen, and
4276 implementing a custom paint engine accelerating the various
4277 painting operations. Then a custom paint device (derived from the
4278 QCustomRasterPaintDevice class) and a custom window surface
4279 (derived from QWSWindowSurface) must be implemented to make
4280 \l{Qt for Embedded Linux} aware of the accelerated driver.
4281
4282 See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
4283 documentation for details.
4284
4285 \sa QRasterPaintEngine, QPaintDevice
4286*/
4287
4288/*!
4289 \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
4290
4291 Constructs a custom raster based paint device for the given
4292 top-level \a widget.
4293*/
4294
4295/*!
4296 \fn int QCustomRasterPaintDevice::bytesPerLine() const
4297
4298 Returns the number of bytes per line in the framebuffer. Note that
4299 this number might be larger than the framebuffer width.
4300*/
4301
4302/*!
4303 \fn int QCustomRasterPaintDevice::devType() const
4304 \internal
4305*/
4306
4307/*!
4308 \fn QImage::Format QCustomRasterPaintDevice::format() const
4309
4310 Returns the format of the device's memory buffet.
4311
4312 The default format is QImage::Format_ARGB32_Premultiplied. The
4313 only other valid format is QImage::Format_RGB16.
4314*/
4315
4316/*!
4317 \fn void * QCustomRasterPaintDevice::memory () const
4318
4319 Returns a pointer to the paint device's memory buffer, or 0 if no
4320 such buffer exists.
4321*/
4322
4323/*!
4324 \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4325 \reimp
4326*/
4327
4328/*!
4329 \fn QSize QCustomRasterPaintDevice::size () const
4330 \internal
4331*/
4332
4333
4334QClipData::QClipData(int height)
4335{
4336 clipSpanHeight = height;
4337 m_clipLines = 0;
4338
4339 allocated = 0;
4340 m_spans = 0;
4341 xmin = xmax = ymin = ymax = 0;
4342 count = 0;
4343
4344 enabled = true;
4345 hasRectClip = hasRegionClip = false;
4346}
4347
4348QClipData::~QClipData()
4349{
4350 if (m_clipLines)
4351 free(m_clipLines);
4352 if (m_spans)
4353 free(m_spans);
4354}
4355
4356void QClipData::initialize()
4357{
4358 if (m_spans)
4359 return;
4360
4361 if (!m_clipLines)
4362 m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4363
4364 Q_CHECK_PTR(m_clipLines);
4365 QT_TRY {
4366 m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4367 allocated = clipSpanHeight;
4368 Q_CHECK_PTR(m_spans);
4369
4370 QT_TRY {
4371 if (hasRectClip) {
4372 int y = 0;
4373 while (y < ymin) {
4374 m_clipLines[y].spans = 0;
4375 m_clipLines[y].count = 0;
4376 ++y;
4377 }
4378
4379 const int len = clipRect.width();
4380 count = 0;
4381 while (y < ymax) {
4382 QSpan *span = m_spans + count;
4383 span->x = xmin;
4384 span->len = len;
4385 span->y = y;
4386 span->coverage = 255;
4387 ++count;
4388