qpaintengine_raster.cpp

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

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9