4#include <QtCore/qglobal.h>
5#include <QtCore/qmutex.h>
7#define QT_FT_BEGIN_HEADER
8#define QT_FT_END_HEADER
10#include <private/qrasterdefs_p.h>
11#include <private/qgrayraster_p.h>
13#include <qpainterpath.h>
21#include <private/qtextengine_p.h>
22#include <private/qfontengine_p.h>
23#include <private/qpixmap_raster_p.h>
25#include <private/qimage_p.h>
26#include <private/qstatictext_p.h>
27#include <private/qcosmeticstroker_p.h>
28#include <private/qdrawhelper_p.h>
29#include <private/qmemrotate_p.h>
30#include <private/qpixellayout_p.h>
31#include <private/qrgba64_p.h>
41# include <qvarlengtharray.h>
42# include <private/qfontengine_p.h>
43# include <qt_windows.h>
53 inline void set(
const QRect &r) {
55 qreal right = r.x() + r.width();
57 qreal bottom = r.y() + r.height();
68 inline void set(
const QRectF &r) {
70 qreal right = r.x() + r.width();
72 qreal bottom = r.y() + r.height();
101#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
102#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
106void dumpClip(
int width,
int height,
const QClipData *clip);
115#define int_dim(pos, dim) (int(pos+dim) - int(pos))
119static inline bool winClearTypeFontsEnabled()
122#if !defined(SPI_GETFONTSMOOTHINGTYPE)
123# define SPI_GETFONTSMOOTHINGTYPE 0x200A
124# define FE_FONTSMOOTHINGCLEARTYPE 0x002
126 SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
127 return result == FE_FONTSMOOTHINGCLEARTYPE;
131
132
133bool QRasterPaintEngine::clearTypeFontsEnabled()
135 static const bool result = winClearTypeFontsEnabled();
144
145
148static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData);
164 ProcessSpans pen_func, ProcessSpans brush_func,
165 QSpanData *pen_data, QSpanData *brush_data);
173static const QRectF boundingRect(
const QPointF *points,
int pointCount)
175 const QPointF *e = points;
176 const QPointF *last = points + pointCount;
177 qreal minx, maxx, miny, maxy;
178 minx = maxx = e->x();
179 miny = maxy = e->y();
183 else if (e->x() > maxx)
187 else if (e->y() > maxy)
190 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
196 ((
QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
201 ((
QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
205 qfixed c2x, qfixed c2y,
206 qfixed ex, qfixed ey,
209 ((
QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
210 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
211 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
215#if !defined(QT_NO_DEBUG) && 0
216static void qt_debug_path(
const QPainterPath &path)
218 const char *names[] = {
225 fprintf(stderr,
"\nQPainterPath: elementCount=%d\n", path.elementCount());
226 for (
int i=0; i<path.elementCount(); ++i) {
227 const QPainterPath::Element &e = path.elementAt(i);
228 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
229 fprintf(stderr,
" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
235 QPaintEngineExPrivate(),
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
273
274
275
278
279
280
281
282
283
284
285QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
286 : QPaintEngineEx(*(
new QRasterPaintEnginePrivate))
288 d_func()->device = device;
293
294
295QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
298 d_func()->device = device;
302void QRasterPaintEngine::init()
304 Q_D(QRasterPaintEngine);
312 d->grayRaster.reset(
new QT_FT_Raster);
313 Q_CHECK_PTR(d->grayRaster.data());
314 if (QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(d->grayRaster.data()))
315 QT_THROW(std::bad_alloc());
318 d->rasterizer.reset(
new QRasterizer);
319 d->rasterBuffer.reset(
new QRasterBuffer());
320 d->outlineMapper.reset(
new QOutlineMapper);
321 d->outlinemapper_xform_dirty =
true;
323 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
324 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
325 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
327 d->baseClip.reset(
new QClipData(d->device->height()));
328 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
330 d->image_filler.init(d->rasterBuffer.data(),
this);
331 d->image_filler.type = QSpanData::Texture;
333 d->image_filler_xform.init(d->rasterBuffer.data(),
this);
334 d->image_filler_xform.type = QSpanData::Texture;
336 d->solid_color_filler.init(d->rasterBuffer.data(),
this);
337 d->solid_color_filler.type = QSpanData::Solid;
339 d->deviceDepth = d->device->depth();
341 d->mono_surface =
false;
342 gccaps &= ~PorterDuff;
344 QImage::Format format = QImage::Format_Invalid;
346 switch (d->device->devType()) {
347 case QInternal::Pixmap:
348 qWarning(
"QRasterPaintEngine: unsupported for pixmaps...");
350 case QInternal::Image:
351 format = d->rasterBuffer->prepare(
static_cast<QImage *>(d->device));
354 qWarning(
"QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
360 case QImage::Format_MonoLSB:
361 case QImage::Format_Mono:
362 d->mono_surface =
true;
365 if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
366 gccaps |= PorterDuff;
373
374
375QRasterPaintEngine::~QRasterPaintEngine()
377 Q_D(QRasterPaintEngine);
379 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*d->grayRaster.data());
383
384
385bool QRasterPaintEngine::begin(QPaintDevice *device)
387 Q_D(QRasterPaintEngine);
389 if (device->devType() == QInternal::Pixmap) {
390 QPixmap *pixmap =
static_cast<QPixmap *>(device);
391 QPlatformPixmap *pd = pixmap->handle();
392 if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass)
393 d->device = pd->buffer();
401 Q_ASSERT(d->device->devType() == QInternal::Image
402 || d->device->devType() == QInternal::CustomRaster);
404 d->systemStateChanged();
406 QRasterPaintEngineState *s = state();
407 ensureOutlineMapper();
408 d->outlineMapper->setClipRect(d->deviceRect);
409 d->rasterizer->setClipRect(d->deviceRect);
411 s->penData.init(d->rasterBuffer.data(),
this);
412 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
413 s->stroker = &d->basicStroker;
414 d->basicStroker.setClipRect(d->deviceRect);
416 s->brushData.init(d->rasterBuffer.data(),
this);
417 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
419 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
421 setDirty(DirtyBrushOrigin);
424 qDebug() <<
"QRasterPaintEngine::begin(" << (
void *) device
425 <<
") devType:" << device->devType()
426 <<
"devRect:" << d->deviceRect;
428 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
433 d->glyphCacheFormat = QFontEngine::Format_Mono;
435 else if (clearTypeFontsEnabled())
440 QImage::Format format =
static_cast<QImage *>(d->device)->format();
441 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
442 d->glyphCacheFormat = QFontEngine::Format_A32;
444 d->glyphCacheFormat = QFontEngine::Format_A8;
446 d->glyphCacheFormat = QFontEngine::Format_A8;
453
454
455bool QRasterPaintEngine::end()
458 Q_D(QRasterPaintEngine);
459 qDebug() <<
"QRasterPaintEngine::end devRect:" << d->deviceRect;
461 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
469
470
471void QRasterPaintEngine::updateMatrix(
const QTransform &matrix)
473 QRasterPaintEngineState *s = state();
476 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
478 ensureOutlineMapper();
534 brushData.tempImage =
nullptr;
535 penData.tempImage =
nullptr;
540
541
542QPainterState *QRasterPaintEngine::createState(QPainterState *orig)
const
544 QRasterPaintEngineState *s;
546 s =
new QRasterPaintEngineState();
548 s =
new QRasterPaintEngineState(*
static_cast<QRasterPaintEngineState *>(orig));
554
555
556void QRasterPaintEngine::setState(QPainterState *s)
558 Q_D(QRasterPaintEngine);
559 QPaintEngineEx::setState(s);
560 QRasterPaintEngineState *t = state();
561 if (t->clip && t->clip->enabled != t->clipEnabled) {
563 t->clip->enabled = t->clipEnabled;
565 d->rasterBuffer->compositionMode = s->composition_mode;
569
570
571
574
575
576
579
580
581void QRasterPaintEngine::penChanged()
584 qDebug() <<
"QRasterPaintEngine::penChanged():" << state()->pen;
586 QRasterPaintEngineState *s = state();
588 s->strokeFlags |= DirtyPen;
589 s->dirty |= DirtyPen;
593
594
595void QRasterPaintEngine::updatePen(
const QPen &pen)
597 Q_D(QRasterPaintEngine);
598 QRasterPaintEngineState *s = state();
600 qDebug() <<
"QRasterPaintEngine::updatePen():" << s->pen;
603 Qt::PenStyle pen_style = qpen_style(pen);
608 s->penData.clip = d->clip();
609 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity,
610 s->composition_mode, s->flags.cosmetic_brush);
612 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
613 || pen.brush().transform().type() >= QTransform::TxNone) {
614 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
620 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
621 pen_style = Qt::SolidLine;
622 s->lastPen.setStyle(Qt::SolidLine);
625 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
626 d->basicStroker.setCapStyle(qpen_capStyle(pen));
627 d->basicStroker.setMiterLimit(pen.miterLimit());
629 qreal penWidth = qpen_widthf(pen);
631 d->basicStroker.setStrokeWidth(1);
633 d->basicStroker.setStrokeWidth(penWidth);
635 if (pen_style == Qt::SolidLine) {
636 s->stroker = &d->basicStroker;
637 }
else if (pen_style != Qt::NoPen) {
639 d->dashStroker.reset(
new QDashStroker(&d->basicStroker));
640 if (pen.isCosmetic()) {
641 d->dashStroker->setClipRect(d->deviceRect);
644 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
645 d->dashStroker->setClipRect(clipRect);
647 d->dashStroker->setDashPattern(pen.dashPattern());
648 d->dashStroker->setDashOffset(pen.dashOffset());
649 s->stroker = d->dashStroker.data();
651 s->stroker =
nullptr;
655 bool cosmetic = pen.isCosmetic();
656 s->flags.fast_pen = pen_style > Qt::NoPen
658 && ((cosmetic && penWidth <= 1)
659 || (!cosmetic && (s->flags.tx_noshear || !s->flags.antialiased) && penWidth * s->txscale <= 1));
661 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
669
670
671void QRasterPaintEngine::brushOriginChanged()
673 QRasterPaintEngineState *s = state();
675 qDebug() <<
"QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
678 s->fillFlags |= DirtyBrushOrigin;
683
684
685void QRasterPaintEngine::brushChanged()
687 QRasterPaintEngineState *s = state();
689 qDebug() <<
"QRasterPaintEngine::brushChanged():" << s->brush;
691 s->fillFlags |= DirtyBrush;
698
699
700void QRasterPaintEngine::updateBrush(
const QBrush &brush)
703 qDebug() <<
"QRasterPaintEngine::updateBrush()" << brush;
705 Q_D(QRasterPaintEngine);
706 QRasterPaintEngineState *s = state();
708 s->brushData.clip = d->clip();
709 s->brushData.setup(brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
710 if (s->fillFlags & DirtyTransform
711 || brush.transform().type() >= QTransform::TxNone)
712 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
713 s->lastBrush = brush;
717void QRasterPaintEngine::updateOutlineMapper()
719 Q_D(QRasterPaintEngine);
720 d->outlineMapper->setMatrix(state()->matrix);
723void QRasterPaintEngine::updateRasterState()
725 QRasterPaintEngineState *s = state();
727 if (s->dirty & DirtyTransform)
728 updateMatrix(s->matrix);
730 if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
731 const QPainter::CompositionMode mode = s->composition_mode;
732 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
733 && s->intOpacity == 256
734 && (mode == QPainter::CompositionMode_SourceOver
735 || (mode == QPainter::CompositionMode_Source
736 && (s->penData.solidColor.spec() != QColor::ExtendedRgb &&
737 s->penData.solidColor.alphaF() >= 1.0f)));
745
746
747void QRasterPaintEngine::opacityChanged()
749 QRasterPaintEngineState *s = state();
752 qDebug() <<
"QRasterPaintEngine::opacityChanged()" << s->opacity;
755 s->fillFlags |= DirtyOpacity;
756 s->strokeFlags |= DirtyOpacity;
757 s->pixmapFlags |= DirtyOpacity;
758 s->dirty |= DirtyOpacity;
759 s->intOpacity = (
int) (s->opacity * 256);
763
764
765void QRasterPaintEngine::compositionModeChanged()
767 Q_D(QRasterPaintEngine);
768 QRasterPaintEngineState *s = state();
771 qDebug() <<
"QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
774 s->fillFlags |= DirtyCompositionMode;
775 s->dirty |= DirtyCompositionMode;
777 s->strokeFlags |= DirtyCompositionMode;
778 d->rasterBuffer->compositionMode = s->composition_mode;
780 d->recalculateFastImages();
784
785
786void QRasterPaintEngine::renderHintsChanged()
788 QRasterPaintEngineState *s = state();
791 qDebug() <<
"QRasterPaintEngine::renderHintsChanged()" << Qt::hex << s->renderHints;
794 bool was_aa = s->flags.antialiased;
795 bool was_bilinear = s->flags.bilinear;
796 bool was_cosmetic_brush = s->flags.cosmetic_brush;
798 s->flags.antialiased =
bool(s->renderHints & QPainter::Antialiasing);
799 s->flags.bilinear =
bool(s->renderHints & QPainter::SmoothPixmapTransform);
800 s->flags.cosmetic_brush = !
bool(s->renderHints & QPainter::NonCosmeticBrushPatterns);
802 if (was_aa != s->flags.antialiased)
803 s->strokeFlags |= DirtyHints;
805 if (was_bilinear != s->flags.bilinear || was_cosmetic_brush != s->flags.cosmetic_brush) {
806 s->strokeFlags |= DirtyPen;
807 s->fillFlags |= DirtyBrush;
810 Q_D(QRasterPaintEngine);
811 d->recalculateFastImages();
813 if (was_aa != s->flags.antialiased)
818
819
820void QRasterPaintEngine::transformChanged()
822 QRasterPaintEngineState *s = state();
825 qDebug() <<
"QRasterPaintEngine::transformChanged()" << s->matrix;
828 s->fillFlags |= DirtyTransform;
829 s->strokeFlags |= DirtyTransform;
831 s->dirty |= DirtyTransform;
833 Q_D(QRasterPaintEngine);
834 d->recalculateFastImages();
838
839
840void QRasterPaintEngine::clipEnabledChanged()
842 QRasterPaintEngineState *s = state();
845 qDebug() <<
"QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
849 s->clip->enabled = s->clipEnabled;
850 s->fillFlags |= DirtyClipEnabled;
851 s->strokeFlags |= DirtyClipEnabled;
852 s->pixmapFlags |= DirtyClipEnabled;
858 SrcOverBlendFunc func,
863 if (alpha == 0 || !clip.isValid())
865 if (pt.x() > qreal(clip.right()) || pt.y() > qreal(clip.bottom()))
867 if ((pt.x() + img.width()) < qreal(clip.left()) || (pt.y() + img.height()) < qreal(clip.top()))
870 Q_ASSERT(img.depth() >= 8);
872 qsizetype srcBPL = img.bytesPerLine();
873 const uchar *srcBits = img.bits();
874 int srcSize = img.depth() >> 3;
875 int iw = img.width();
876 int ih = img.height();
882 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
886 int x = qRound(pt.x());
888 int cx2 = clip.x() + clip.width();
891 srcBits += srcSize * d;
896 int d = x + iw - cx2;
904 int cy2 = clip.y() + clip.height();
905 int y = qRound(pt.y());
908 srcBits += srcBPL * d;
913 int d = y + ih - cy2;
920 int dstSize = rasterBuffer->bytesPerPixel();
921 qsizetype dstBPL = rasterBuffer->bytesPerLine();
922 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
935 if (pt.x() > qreal(clip.right()) || pt.y() > qreal(clip.bottom()))
937 if ((pt.x() + img.width()) < qreal(clip.left()) || (pt.y() + img.height()) < qreal(clip.top()))
940 Q_ASSERT(img.depth() >= 8);
942 qsizetype srcBPL = img.bytesPerLine();
943 const uchar *srcBits = img.bits();
944 int srcSize = img.depth() >> 3;
945 int iw = img.width();
946 int ih = img.height();
952 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
956 int x = qRound(pt.x());
958 int cx2 = clip.x() + clip.width();
961 srcBits += srcSize * d;
966 int d = x + iw - cx2;
974 int cy2 = clip.y() + clip.height();
975 int y = qRound(pt.y());
978 srcBits += srcBPL * d;
983 int d = y + ih - cy2;
990 int dstSize = rasterBuffer->bytesPerPixel();
991 qsizetype dstBPL = rasterBuffer->bytesPerLine();
992 const uint *src = (
const uint *) srcBits;
993 uint *dst =
reinterpret_cast<uint *>(rasterBuffer->buffer() + x * dstSize + y * dstBPL);
995 const int len = iw * (qt_depthForFormat(rasterBuffer->format) >> 3);
996 for (
int y = 0; y < ih; ++y) {
997 memcpy(dst, src, len);
998 dst = (quint32 *)(((uchar *) dst) + dstBPL);
999 src = (
const quint32 *)(((
const uchar *) src) + srcBPL);
1006 deviceRectUnclipped = QRect(0, 0,
1007 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1008 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1010 if (!systemClip.isEmpty()) {
1011 QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
1012 deviceRect = clippedDeviceRgn.boundingRect();
1013 baseClip->setClipRegion(clippedDeviceRgn);
1015 deviceRect = deviceRectUnclipped;
1016 baseClip->setClipRect(deviceRect);
1019 qDebug() <<
"systemStateChanged" <<
this <<
"deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
1022 exDeviceRect = deviceRect;
1024 Q_Q(QRasterPaintEngine);
1026 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1027 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1028 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1034 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1037 Q_Q(QRasterPaintEngine);
1038 bool bilinear = q->state()->flags.bilinear;
1040 if (b.d->transform.type() > QTransform::TxNone) {
1041 spanData->setupMatrix(b.transform() * m, bilinear);
1043 if (m.type() <= QTransform::TxTranslate) {
1053 spanData->dx = -m.dx();
1054 spanData->dy = -m.dy();
1055 spanData->txop = m.type();
1056 spanData->bilinear = bilinear;
1057 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1058 spanData->adjustSpanMethods();
1060 spanData->setupMatrix(m, bilinear);
1067#ifdef QT_CLIPPING_RATIOS
1072static void checkClipRatios(QRasterPaintEnginePrivate *d)
1074 if (d->clip()->hasRectClip)
1076 if (d->clip()->hasRegionClip)
1080 if ((totalClips % 5000) == 0) {
1081 printf(
"Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1082 rectClips * 100.0 / (qreal) totalClips,
1083 regionClips * 100.0 / (qreal) totalClips,
1084 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1103 s->fillFlags |= QPaintEngine::DirtyClipPath;
1104 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1105 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1107 d->solid_color_filler.clip = d
->clip();
1108 d->solid_color_filler.adjustSpanMethods();
1111 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1118
1119
1120void QRasterPaintEngine::clip(
const QVectorPath &path, Qt::ClipOperation op)
1123 qDebug() <<
"QRasterPaintEngine::clip(): " << path << op;
1125 if (path.elements()) {
1126 for (
int i=0; i<path.elementCount(); ++i) {
1127 qDebug() <<
" - " << path.elements()[i]
1128 <<
'(' << path.points()[i*2] <<
", " << path.points()[i*2+1] <<
')';
1131 for (
int i=0; i<path.elementCount(); ++i) {
1132 qDebug() <<
" ---- "
1133 <<
'(' << path.points()[i*2] <<
", " << path.points()[i*2+1] <<
')';
1138 Q_D(QRasterPaintEngine);
1139 QRasterPaintEngineState *s = state();
1142 if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
1143 if (s->matrix.type() <= QTransform::TxScale
1146 qDebug(
" --- optimizing vector clip to rect clip...");
1148 const qreal *points = path.points();
1149 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1150 if (setClipRectInDeviceCoords(qt_mapFillRect(r, s->matrix), op))
1155 if (op == Qt::NoClip) {
1156 qrasterpaintengine_state_setNoClip(s);
1159 QClipData *base = d->baseClip.data();
1162 if (op == Qt::IntersectClip && s->clip)
1168 Qt::ClipOperation isectOp = Qt::IntersectClip;
1169 if (base ==
nullptr)
1170 isectOp = Qt::ReplaceClip;
1172 QClipData *newClip =
new QClipData(d->rasterBuffer->height());
1173 newClip->initialize();
1174 ClipData clipData = { base, newClip, isectOp };
1175 ensureOutlineMapper();
1176 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData,
nullptr);
1180 if (s->flags.has_clip_ownership)
1184 s->flags.has_clip_ownership =
true;
1186 qrasterpaintengine_dirty_clip(d, s);
1192
1193
1194void QRasterPaintEngine::clip(
const QRect &rect, Qt::ClipOperation op)
1197 qDebug() <<
"QRasterPaintEngine::clip(): " << rect << op;
1200 QRasterPaintEngineState *s = state();
1202 if (op == Qt::NoClip) {
1203 qrasterpaintengine_state_setNoClip(s);
1205 }
else if (s->matrix.type() > QTransform::TxScale) {
1206 QPaintEngineEx::clip(rect, op);
1209 }
else if (!setClipRectInDeviceCoords(qt_mapFillRect(rect, s->matrix), op)) {
1210 QPaintEngineEx::clip(rect, op);
1216bool QRasterPaintEngine::setClipRectInDeviceCoords(
const QRect &r, Qt::ClipOperation op)
1218 Q_D(QRasterPaintEngine);
1219 QRect clipRect = r & d->deviceRect;
1220 QRasterPaintEngineState *s = state();
1222 if (op == Qt::ReplaceClip || s->clip ==
nullptr) {
1226 QRegion clipRegion = systemClip();
1227 QClipData *clip =
new QClipData(d->rasterBuffer->height());
1229 if (clipRegion.isEmpty())
1230 clip->setClipRect(clipRect);
1232 clip->setClipRegion(clipRegion & clipRect);
1234 if (s->flags.has_clip_ownership)
1238 s->clip->enabled =
true;
1239 s->flags.has_clip_ownership =
true;
1241 }
else if (op == Qt::IntersectClip){
1242 QClipData *base = s->clip;
1245 if (base->hasRectClip || base->hasRegionClip) {
1246 if (!s->flags.has_clip_ownership) {
1247 s->clip =
new QClipData(d->rasterBuffer->height());
1248 s->flags.has_clip_ownership =
true;
1250 if (base->hasRectClip)
1251 s->clip->setClipRect(base->clipRect & clipRect);
1253 s->clip->setClipRegion(base->clipRegion & clipRect);
1254 s->clip->enabled =
true;
1262 qrasterpaintengine_dirty_clip(d, s);
1268
1269
1270void QRasterPaintEngine::clip(
const QRegion ®ion, Qt::ClipOperation op)
1273 qDebug() <<
"QRasterPaintEngine::clip(): " << region << op;
1276 Q_D(QRasterPaintEngine);
1278 if (region.rectCount() == 1) {
1279 clip(region.boundingRect(), op);
1283 QRasterPaintEngineState *s = state();
1284 const QClipData *clip = d->clip();
1285 const QClipData *baseClip = d->baseClip.data();
1287 if (op == Qt::NoClip) {
1288 qrasterpaintengine_state_setNoClip(s);
1289 }
else if (s->matrix.type() > QTransform::TxScale
1290 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1291 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1292 QPaintEngineEx::clip(region, op);
1294 const QClipData *curClip;
1297 if (op == Qt::IntersectClip)
1302 if (s->flags.has_clip_ownership) {
1306 newClip =
new QClipData(d->rasterBuffer->height());
1308 s->flags.has_clip_ownership =
true;
1311 QRegion r = s->matrix.map(region);
1312 if (curClip->hasRectClip)
1313 newClip->setClipRegion(r & curClip->clipRect);
1314 else if (curClip->hasRegionClip)
1315 newClip->setClipRegion(r & curClip->clipRegion);
1317 qrasterpaintengine_dirty_clip(d, s);
1322
1323
1324
1325
1329
1330
1331void QRasterPaintEngine::fillPath(
const QPainterPath &path, QSpanData *fillData)
1334 qDebug() <<
" --- fillPath, bounds=" << path.boundingRect();
1337 if (!fillData->blend)
1340 Q_D(QRasterPaintEngine);
1342 const QRectF controlPointRect = path.controlPointRect();
1344 QRasterPaintEngineState *s = state();
1345 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1346 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1347 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1348 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1349 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1350 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1352 if (!s->flags.antialiased && !do_clip) {
1353 d->initializeRasterizer(fillData);
1354 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1358 ensureOutlineMapper();
1359 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1367 bool rectClipped =
true;
1370 x1 = qMax(r.x(), data->clip->xmin);
1371 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1372 y1 = qMax(r.y(), data->clip->ymin);
1373 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1374 rectClipped = data->clip->hasRectClip;
1377 x1 = qMax(r.x(), pe->deviceRect.x());
1378 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1379 y1 = qMax(r.y(), pe->deviceRect.y());
1380 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1382 x1 = qMax(r.x(), 0);
1383 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1384 y1 = qMax(r.y(), 0);
1385 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1388 if (x2 <= x1 || y2 <= y1)
1391 const int width = x2 - x1;
1392 const int height = y2 - y1;
1394 bool isUnclipped = rectClipped
1395 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1397 if (pe && isUnclipped) {
1398 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1400 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1401 || (mode == QPainter::CompositionMode_SourceOver
1402 && (data->solidColor.spec() != QColor::ExtendedRgb &&
1403 data->solidColor.alphaF() >= 1.0f))))
1405 data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor.rgba64());
1410 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1412 const int nspans = 512;
1413 Q_DECL_UNINITIALIZED QT_FT_Span spans[nspans];
1415 Q_ASSERT(data->blend);
1418 int n = qMin(nspans, y2 - y);
1422 spans[i].len = width;
1424 spans[i].coverage = 255;
1428 blend(n, spans, data);
1434
1435
1436void QRasterPaintEngine::drawRects(
const QRect *rects,
int rectCount)
1439 qDebug(
" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1441 Q_D(QRasterPaintEngine);
1442 ensureRasterState();
1443 QRasterPaintEngineState *s = state();
1447 if (s->brushData.blend) {
1448 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1449 const QRect *r = rects;
1450 const QRect *lastRect = rects + rectCount;
1452 int offset_x =
int(s->matrix.dx());
1453 int offset_y =
int(s->matrix.dy());
1454 while (r < lastRect) {
1455 QRect rect = r->normalized();
1456 QRect rr = rect.translated(offset_x, offset_y);
1457 fillRect_normalized(rr, &s->brushData, d);
1461 QRectVectorPath path;
1462 for (
int i=0; i<rectCount; ++i) {
1464 fill(path, s->brush);
1470 if (s->penData.blend) {
1471 QRectVectorPath path;
1472 if (s->flags.fast_pen) {
1473 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1474 for (
int i = 0; i < rectCount; ++i) {
1476 stroker.drawPath(path);
1479 for (
int i = 0; i < rectCount; ++i) {
1481 stroke(path, s->pen);
1488
1489
1490void QRasterPaintEngine::drawRects(
const QRectF *rects,
int rectCount)
1493 qDebug(
" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1496 Q_D(QRasterPaintEngine);
1497 ensureRasterState();
1498 QRasterPaintEngineState *s = state();
1501 if (s->flags.tx_noshear) {
1503 if (s->brushData.blend) {
1504 d->initializeRasterizer(&s->brushData);
1505 for (
int i = 0; i < rectCount; ++i) {
1506 const QRectF &rect = rects[i].normalized();
1509 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1510 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1511 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1516 if (s->penData.blend) {
1517 QRectVectorPath path;
1518 if (s->flags.fast_pen) {
1519 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1520 for (
int i = 0; i < rectCount; ++i) {
1522 stroker.drawPath(path);
1525 for (
int i = 0; i < rectCount; ++i) {
1527 QPaintEngineEx::stroke(path, s->lastPen);
1535 QPaintEngineEx::drawRects(rects, rectCount);
1540
1541
1542void QRasterPaintEngine::stroke(
const QVectorPath &path,
const QPen &pen)
1544 Q_D(QRasterPaintEngine);
1545 QRasterPaintEngineState *s = state();
1548 if (!s->penData.blend)
1551 if (s->flags.fast_pen) {
1552 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1553 stroker.drawPath(path);
1554 }
else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1555 qreal width = s->lastPen.isCosmetic()
1556 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1557 : qpen_widthf(s->lastPen) * s->txscale;
1559 qreal dashOffset = s->lastPen.dashOffset();
1561 qreal patternLength = 0;
1562 const QList<qreal> pattern = s->lastPen.dashPattern();
1563 for (
int i = 0; i < pattern.size(); ++i)
1564 patternLength += pattern.at(i);
1566 if (patternLength > 0) {
1567 dashOffset = std::fmod(dashOffset, patternLength);
1569 dashOffset += patternLength;
1570 while (dashOffset >= pattern.at(dashIndex)) {
1571 dashOffset -= pattern.at(dashIndex);
1572 if (++dashIndex >= pattern.size())
1578 Q_D(QRasterPaintEngine);
1579 d->initializeRasterizer(&s->penData);
1580 int lineCount = path.elementCount() / 2;
1581 const QLineF *lines =
reinterpret_cast<
const QLineF *>(path.points());
1583 for (
int i = 0; i < lineCount; ++i) {
1584 const QLineF line = s->matrix.map(lines[i]);
1585 if (line.p1() == line.p2()) {
1586 if (s->lastPen.capStyle() != Qt::FlatCap) {
1587 const QPointF delta(width / 2, 0);
1588 d->rasterizer->rasterizeLine(line.p1() - delta, line.p1() + delta, 1);
1593 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1594 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1595 width / line.length(),
1596 s->lastPen.capStyle() == Qt::SquareCap);
1599 int dIndex = dashIndex;
1600 qreal dOffset = dashOffset;
1602 d->rasterizeLine_dashed(line, width, &dIndex, &dOffset, &inD);
1607 QPaintEngineEx::stroke(path, pen);
1610QRect QRasterPaintEngine::toNormalizedFillRect(
const QRectF &rect)
1612 int x1 = qRound(rect.x());
1613 int y1 = qRound(rect.y());
1614 int x2 = qRound(rect.right());
1615 int y2 = qRound(rect.bottom());
1622 return QRect(x1, y1, x2 - x1, y2 - y1);
1626
1627
1628void QRasterPaintEngine::fill(
const QVectorPath &path,
const QBrush &brush)
1633 QRectF rf = path.controlPointRect();
1634 qDebug() <<
"QRasterPaintEngine::fill(): "
1635 <<
"size=" << path.elementCount()
1636 <<
", hints=" << Qt::hex << path.hints()
1640 Q_D(QRasterPaintEngine);
1641 QRasterPaintEngineState *s = state();
1644 if (!s->brushData.blend)
1647 if (path.shape() == QVectorPath::RectangleHint) {
1648 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1649 const qreal *p = path.points();
1650 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1651 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1652 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1655 ensureRasterState();
1656 if (s->flags.tx_noshear) {
1657 d->initializeRasterizer(&s->brushData);
1659 const qreal *p = path.points();
1660 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1662 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1663 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1664 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1671 QRectF cpRect = path.controlPointRect();
1672 const QRectF pathDeviceRect = s->matrix.mapRect(cpRect);
1674 if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid())
1677 ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData);
1692 ensureOutlineMapper();
1693 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1696void QRasterPaintEngine::fillRect(
const QRectF &r, QSpanData *data)
1698 Q_D(QRasterPaintEngine);
1699 QRasterPaintEngineState *s = state();
1701 if (!s->flags.antialiased) {
1702 uint txop = s->matrix.type();
1703 if (txop == QTransform::TxNone) {
1704 fillRect_normalized(toNormalizedFillRect(r), data, d);
1706 }
else if (txop == QTransform::TxTranslate) {
1707 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1708 fillRect_normalized(rr, data, d);
1710 }
else if (txop == QTransform::TxScale) {
1711 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1712 fillRect_normalized(rr, data, d);
1716 ensureRasterState();
1717 if (s->flags.tx_noshear) {
1718 d->initializeRasterizer(data);
1719 QRectF nr = r.normalized();
1720 if (!nr.isEmpty()) {
1721 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1722 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1723 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1730 ensureOutlineMapper();
1731 fillPath(path, data);
1735
1736
1737void QRasterPaintEngine::fillRect(
const QRectF &r,
const QBrush &brush)
1740 qDebug() <<
"QRasterPaintEngine::fillRecct(): " << r << brush;
1742 QRasterPaintEngineState *s = state();
1745 if (!s->brushData.blend)
1748 fillRect(r, &s->brushData);
1754 return Qt::transparent;
1755 if (c.spec() == QColor::ExtendedRgb) {
1757 c.getRgbF(&r, &g, &b, &a);
1758 a = a * alpha * (1.f / 256.f);
1759 return QColor::fromRgbF(r * a, g * a, b * a, a);
1761 return qPremultiply(combineAlpha256(c.rgba64(), alpha));
1765
1766
1767void QRasterPaintEngine::fillRect(
const QRectF &r,
const QColor &color)
1770 qDebug() <<
"QRasterPaintEngine::fillRect(): " << r << color;
1772 Q_D(QRasterPaintEngine);
1773 QRasterPaintEngineState *s = state();
1775 d->solid_color_filler.solidColor = qPremultiplyWithExtraAlpha(color, s->intOpacity);
1777 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f
1778 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1781 d->solid_color_filler.clip = d->clip();
1782 d->solid_color_filler.adjustSpanMethods();
1783 fillRect(r, &d->solid_color_filler);
1786static inline bool isAbove(
const QPointF *a,
const QPointF *b)
1788 return a->y() < b->y();
1791static bool splitPolygon(
const QPointF *points,
int pointCount, QList<QPointF> *upper, QList<QPointF> *lower)
1796 Q_ASSERT(pointCount >= 2);
1798 QList<
const QPointF *> sorted;
1799 sorted.reserve(pointCount);
1801 upper->reserve(pointCount * 3 / 4);
1802 lower->reserve(pointCount * 3 / 4);
1804 for (
int i = 0; i < pointCount; ++i)
1805 sorted << points + i;
1807 std::sort(sorted.begin(), sorted.end(), isAbove);
1809 qreal splitY = sorted.at(sorted.size() / 2)->y();
1811 const QPointF *end = points + pointCount;
1812 const QPointF *last = end - 1;
1814 QList<QPointF> *bin[2] = { upper, lower };
1816 for (
const QPointF *p = points; p < end; ++p) {
1817 int side = p->y() < splitY;
1818 int lastSide = last->y() < splitY;
1820 if (side != lastSide) {
1821 if (qFuzzyCompare(p->y(), splitY)) {
1822 bin[!side]->append(*p);
1823 }
else if (qFuzzyCompare(last->y(), splitY)) {
1824 bin[side]->append(*last);
1826 QPointF delta = *p - *last;
1827 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1829 bin[0]->append(intersection);
1830 bin[1]->append(intersection);
1834 bin[side]->append(*p);
1840 return upper->size() < pointCount && lower->size() < pointCount;
1844
1845
1846void QRasterPaintEngine::fillPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1848 Q_D(QRasterPaintEngine);
1849 QRasterPaintEngineState *s = state();
1851 const int maxPoints = 0xffff;
1854 if (pointCount > maxPoints) {
1855 QList<QPointF> upper, lower;
1857 if (splitPolygon(points, pointCount, &upper, &lower)) {
1858 fillPolygon(upper.constData(), upper.size(), mode);
1859 fillPolygon(lower.constData(), lower.size(), mode);
1861 qWarning(
"Polygon too complex for filling.");
1867 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1868 ensureOutlineMapper();
1869 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1872 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1874 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1878
1879
1880void QRasterPaintEngine::drawPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1882 Q_D(QRasterPaintEngine);
1883 QRasterPaintEngineState *s = state();
1886 qDebug(
" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1887 for (
int i=0; i<pointCount; ++i)
1888 qDebug() <<
" - " << points[i];
1890 Q_ASSERT(pointCount >= 2);
1892 if (mode != PolylineMode && QVectorPath::isRect((
const qreal *) points, pointCount)) {
1893 QRectF r(points[0], points[2]);
1899 if (mode != PolylineMode) {
1902 if (s->brushData.blend)
1903 fillPolygon(points, pointCount, mode);
1907 if (s->penData.blend) {
1908 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1909 if (s->flags.fast_pen) {
1910 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1911 stroker.drawPath(vp);
1913 QPaintEngineEx::stroke(vp, s->lastPen);
1919
1920
1921void QRasterPaintEngine::drawPolygon(
const QPoint *points,
int pointCount, PolygonDrawMode mode)
1923 Q_D(QRasterPaintEngine);
1924 QRasterPaintEngineState *s = state();
1927 qDebug(
" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1928 for (
int i=0; i<pointCount; ++i)
1929 qDebug() <<
" - " << points[i];
1931 Q_ASSERT(pointCount >= 2);
1932 if (mode != PolylineMode && QVectorPath::isRect((
const int *) points, pointCount)) {
1933 QRect r(points[0].x(),
1935 points[2].x() - points[0].x(),
1936 points[2].y() - points[0].y());
1944 if (mode != PolylineMode) {
1946 if (s->brushData.blend) {
1948 ensureOutlineMapper();
1949 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1950 d->outlineMapper->moveTo(*points);
1951 const QPoint *p = points;
1952 const QPoint *ep = points + pointCount - 1;
1954 d->outlineMapper->lineTo(*(++p));
1956 d->outlineMapper->endOutline();
1959 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1961 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
1966 if (s->penData.blend) {
1967 int count = pointCount * 2;
1968 QVarLengthArray<qreal> fpoints(count);
1969 for (
int i=0; i<count; ++i)
1970 fpoints[i] = ((
const int *) points)[i];
1971 QVectorPath vp((qreal *) fpoints.data(), pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1973 if (s->flags.fast_pen) {
1974 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1975 stroker.drawPath(vp);
1977 QPaintEngineEx::stroke(vp, s->lastPen);
1983
1984
1985void QRasterPaintEngine::drawPixmap(
const QPointF &pos,
const QPixmap &pixmap)
1988 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), pos=" << pos <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
1991 QPlatformPixmap *pd = pixmap.handle();
1992 if (pd->classId() == QPlatformPixmap::RasterClass) {
1993 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
1994 if (image.depth() == 1) {
1995 Q_D(QRasterPaintEngine);
1996 QRasterPaintEngineState *s = state();
1997 if (s->matrix.type() <= QTransform::TxTranslate) {
1999 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2001 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2004 QRasterPaintEngine::drawImage(pos, image);
2007 const QImage image = pixmap.toImage();
2008 if (pixmap.depth() == 1) {
2009 Q_D(QRasterPaintEngine);
2010 QRasterPaintEngineState *s = state();
2011 if (s->matrix.type() <= QTransform::TxTranslate) {
2013 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2015 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2018 QRasterPaintEngine::drawImage(pos, image);
2024
2025
2026void QRasterPaintEngine::drawPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QRectF &sr)
2029 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), r=" << r <<
" sr=" << sr <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
2032 QPlatformPixmap* pd = pixmap.handle();
2033 if (pd->classId() == QPlatformPixmap::RasterClass) {
2034 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2035 if (image.depth() == 1) {
2036 Q_D(QRasterPaintEngine);
2037 QRasterPaintEngineState *s = state();
2038 if (s->matrix.type() <= QTransform::TxTranslate
2039 && r.size() == sr.size()
2040 && r.size() == pixmap.size()) {
2042 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2045 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2048 drawImage(r, image, sr);
2051 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2052 const QImage image = pd->toImage(clippedSource);
2053 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2054 if (image.depth() == 1) {
2055 Q_D(QRasterPaintEngine);
2056 QRasterPaintEngineState *s = state();
2057 if (s->matrix.type() <= QTransform::TxTranslate
2058 && r.size() == sr.size()
2059 && r.size() == pixmap.size()) {
2061 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2064 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2067 drawImage(r, image, translatedSource);
2074 const int iv =
int(v);
2083 const int xmin =
int(rect.x());
2084 const int xmax =
int(fast_ceil_positive(rect.right()));
2085 const int ymin =
int(rect.y());
2086 const int ymax =
int(fast_ceil_positive(rect.bottom()));
2087 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2091
2092
2093void QRasterPaintEngine::drawImage(
const QPointF &p,
const QImage &img)
2096 qDebug() <<
" - QRasterPaintEngine::drawImage(), p=" << p <<
" image=" << img.size() <<
"depth=" << img.depth();
2099 Q_D(QRasterPaintEngine);
2100 QRasterPaintEngineState *s = state();
2101 qreal scale = img.devicePixelRatio();
2103 if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) {
2104 drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
2106 QRectF(0, 0, img.width(), img.height()));
2109 const QClipData *clip = d->clip();
2110 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2112 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, img.rect())) {
2114 d->blitImage(pt, img, d->deviceRect);
2116 }
else if (clip->hasRectClip) {
2117 d->blitImage(pt, img, clip->clipRect);
2120 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2121 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2124 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2126 }
else if (clip->hasRectClip) {
2127 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2135 d->image_filler.clip = clip;
2136 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2137 if (!d->image_filler.blend)
2139 d->image_filler.dx = -pt.x();
2140 d->image_filler.dy = -pt.y();
2141 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2143 fillRect_normalized(rr, &d->image_filler, d);
2150 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2161 inline RotationType qRotationType(
const QTransform &transform)
2163 QTransform::TransformationType type = transform.type();
2165 if (type > QTransform::TxRotate)
2168 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2169 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2172 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2173 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2176 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2177 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2183 inline bool isPixelAligned(
const QPointF &pt)
2185 return QPointF(pt.toPoint()) == pt;
2187 inline bool isPixelAligned(
const QRectF &rect)
2189 return QRectF(rect.toRect()) == rect;
2194
2195
2196void QRasterPaintEngine::drawImage(
const QRectF &r,
const QImage &img,
const QRectF &sr,
2197 Qt::ImageConversionFlags)
2200 qDebug() <<
" - QRasterPaintEngine::drawImage(), r=" << r <<
" sr=" << sr <<
" image=" << img.size() <<
"depth=" << img.depth();
2206 Q_D(QRasterPaintEngine);
2207 QRasterPaintEngineState *s = state();
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;
2214 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2217 QTransform old = s->matrix;
2220 QRgb color = img.pixel(sr_l, sr_t);
2221 if (img.pixelFormat().premultiplied() == QPixelFormat::Premultiplied) {
2223 d->solid_color_filler.solidColor = multiplyAlpha256(QRgba64::fromArgb32(color), s->intOpacity);
2225 d->solid_color_filler.solidColor = qPremultiply(combineAlpha256(QRgba64::fromArgb32(color), s->intOpacity));
2228 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f && s->composition_mode == QPainter::CompositionMode_SourceOver)
2231 d->solid_color_filler.clip = d->clip();
2232 d->solid_color_filler.adjustSpanMethods();
2233 fillRect(r, &d->solid_color_filler);
2239 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2241 const QClipData *clip = d->clip();
2243 if (s->matrix.type() == QTransform::TxRotate
2245 && (!clip || clip->hasRectClip)
2246 && s->intOpacity == 256
2247 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2248 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
2250 RotationType rotationType = qRotationType(s->matrix);
2251 Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats);
2252 const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
2254 if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2255 QRectF transformedTargetRect = s->matrix.mapRect(r);
2257 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, transformedTargetRect.topRight(), sr)) {
2258 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2259 if (clippedTransformedTargetRect.isNull())
2262 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2264 QRect clippedSourceRect
2265 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2266 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2268 clippedSourceRect = clippedSourceRect.intersected(img.rect());
2270 const qsizetype dbpl = d->rasterBuffer->bytesPerLine();
2271 const qsizetype sbpl = img.bytesPerLine();
2273 uchar *dst = d->rasterBuffer->buffer();
2274 uint bpp = img.depth() >> 3;
2276 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2277 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2279 uint cw = clippedSourceRect.width();
2280 uint ch = clippedSourceRect.height();
2282 qMemRotateFunctions[plBpp][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2289 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2291 QRectF targetBounds = s->matrix.mapRect(r);
2292 bool exceedsPrecision = r.width() > 0x7fff
2293 || r.height() > 0x7fff
2294 || targetBounds.left() < -0x7fff
2295 || targetBounds.top() < -0x7fff
2296 || targetBounds.right() > 0x7fff
2297 || targetBounds.bottom() > 0x7fff
2298 || targetBounds.width() > 0x7fff
2299 || targetBounds.height() > 0x7fff
2300 || s->matrix.m11() >= 512
2301 || s->matrix.m22() >= 512;
2302 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2303 if (s->matrix.type() > QTransform::TxScale) {
2304 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2307 if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) {
2308 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2309 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2310 s->matrix, s->intOpacity);
2315 bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
2316 bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
2317 if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
2318 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2320 QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
2322 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2324 }
else if (clip->hasRectClip) {
2325 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2330 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2331 if (func && (!clip || clip->hasRectClip)) {
2332 QRectF tr = qt_mapRect_non_normalizing(r, s->matrix);
2333 if (!s->flags.antialiased) {
2334 tr.setX(qRound(tr.x()));
2335 tr.setY(qRound(tr.y()));
2336 tr.setWidth(qRound(tr.width()));
2337 tr.setHeight(qRound(tr.height()));
2339 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2340 img.bits(), img.bytesPerLine(), img.height(),
2342 !clip ? d->deviceRect : clip->clipRect,
2349 QTransform copy = s->matrix;
2350 copy.translate(r.x(), r.y());
2352 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2353 copy.translate(-sr.x(), -sr.y());
2355 d->image_filler_xform.clip = clip;
2356 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2357 if (!d->image_filler_xform.blend)
2359 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2361 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2362 QRectF rr = s->matrix.mapRect(r);
2364 const int x1 = qRound(rr.x());
2365 const int y1 = qRound(rr.y());
2366 const int x2 = qRound(rr.right());
2367 const int y2 = qRound(rr.bottom());
2369 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2374 ensureRasterState();
2375 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2376 d->initializeRasterizer(&d->image_filler_xform);
2377 d->rasterizer->setAntialiased(s->flags.antialiased);
2379 const QRectF &rect = r.normalized();
2380 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2381 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2383 if (s->flags.tx_noshear)
2384 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2386 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2392 QTransform m = s->matrix;
2393 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2394 m.m21(), m.m22(), m.m23(),
2395 m.m31(), m.m32(), m.m33());
2396 fillPath(path, &d->image_filler_xform);
2399 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2400 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, sr)) {
2402 d->blitImage(pt, img, d->deviceRect, sr.toRect());
2404 }
else if (clip->hasRectClip) {
2405 d->blitImage(pt, img, clip->clipRect, sr.toRect());
2408 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2409 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2412 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2414 }
else if (clip->hasRectClip) {
2415 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2421 d->image_filler.clip = clip;
2422 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2423 if (!d->image_filler.blend)
2425 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2426 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2429 rr.translate(s->matrix.dx(), s->matrix.dy());
2431 const int x1 = qRound(rr.x());
2432 const int y1 = qRound(rr.y());
2433 const int x2 = qRound(rr.right());
2434 const int y2 = qRound(rr.bottom());
2436 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2441
2442
2443void QRasterPaintEngine::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sr)
2446 qDebug() <<
" - QRasterPaintEngine::drawTiledPixmap(), r=" << r <<
"pixmap=" << pixmap.size();
2448 Q_D(QRasterPaintEngine);
2449 QRasterPaintEngineState *s = state();
2454 QPlatformPixmap *pd = pixmap.handle();
2455 if (pd->classId() == QPlatformPixmap::RasterClass) {
2456 image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2458 image = pixmap.toImage();
2461 if (image.depth() == 1)
2462 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2464 const qreal pixmapDevicePixelRatio = pixmap.devicePixelRatio();
2465 if (s->matrix.type() > QTransform::TxTranslate || pixmapDevicePixelRatio > qreal(1.0)) {
2466 QTransform copy = s->matrix;
2467 copy.translate(r.x(), r.y());
2468 copy.translate(-sr.x(), -sr.y());
2469 const qreal inverseDpr = qreal(1.0) / pixmapDevicePixelRatio;
2470 copy.scale(inverseDpr, inverseDpr);
2471 d->image_filler_xform.clip = d->clip();
2472 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2473 if (!d->image_filler_xform.blend)
2475 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2478 ensureRasterState();
2479 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2480 d->initializeRasterizer(&d->image_filler_xform);
2481 d->rasterizer->setAntialiased(s->flags.antialiased);
2483 const QRectF &rect = r.normalized();
2484 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2485 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2486 if (s->flags.tx_noshear)
2487 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2489 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2495 fillPath(path, &d->image_filler_xform);
2497 d->image_filler.clip = d->clip();
2499 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2500 if (!d->image_filler.blend)
2502 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2503 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2506 rr.translate(s->matrix.dx(), s->matrix.dy());
2507 fillRect_normalized(rr.normalized().toRect(), &d->image_filler, d);
2515 return (s[x>>3] << (x&7)) & 0x80;
2519
2520
2521QRasterBuffer *QRasterPaintEngine::rasterBuffer()
2523 Q_D(QRasterPaintEngine);
2524 return d->rasterBuffer.data();
2528
2529
2530void QRasterPaintEngine::alphaPenBlt(
const void* src,
int bpl,
int depth,
int rx,
int ry,
int w,
int h,
bool useGammaCorrection)
2532 Q_D(QRasterPaintEngine);
2533 QRasterPaintEngineState *s = state();
2535 if (!s->penData.blend)
2538 QRasterBuffer *rb = d->rasterBuffer.data();
2539 if (rb->colorSpace.transferFunction() == QColorSpace::TransferFunction::Linear)
2540 useGammaCorrection =
false;
2542 const QRect rect(rx, ry, w, h);
2543 const QClipData *clip = d->clip();
2544 bool unclipped =
false;
2547 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2548 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2550 if (clip->hasRectClip) {
2551 unclipped = rx > clip->xmin
2552 && rx + w < clip->xmax
2554 && ry + h < clip->ymax;
2561 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2562 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2567 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2568 && rect.top() >= 0 && rect.bottom() < rb->height();
2570 unclipped = contains && d->isUnclipped_normalized(rect);
2573 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2574 const uchar * scanline =
static_cast<
const uchar *>(src);
2576 if (s->flags.fast_text) {
2579 if (s->penData.bitmapBlit) {
2580 s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2581 scanline, w, h, bpl);
2584 }
else if (depth == 8) {
2585 if (s->penData.alphamapBlit) {
2586 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2587 scanline, w, h, bpl,
nullptr, useGammaCorrection);
2590 }
else if (depth == 32) {
2592 if (s->penData.alphaRGBBlit) {
2593 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2594 (
const uint *) scanline, w, h, bpl / 4,
nullptr, useGammaCorrection);
2598 }
else if ((depth == 8 && s->penData.alphamapBlit) || (depth == 32 && s->penData.alphaRGBBlit)) {
2601 int nx = qMax(0, rx);
2602 int ny = qMax(0, ry);
2605 int xdiff = nx - rx;
2606 int ydiff = ny - ry;
2607 scanline += ydiff * bpl;
2608 scanline += xdiff * (depth == 32 ? 4 : 1);
2613 if (nx + w > d->rasterBuffer->width())
2614 w = d->rasterBuffer->width() - nx;
2615 if (ny + h > d->rasterBuffer->height())
2616 h = d->rasterBuffer->height() - ny;
2622 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2623 scanline, w, h, bpl, clip, useGammaCorrection);
2624 else if (depth == 32)
2625 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2626 (
const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
2640 scanline += bpl * y0;
2644 w = qMin(w, rb->width() - qMax(0, rx));
2645 h = qMin(h, rb->height() - qMax(0, ry));
2647 if (w <= 0 || h <= 0)
2650 const int NSPANS = 512;
2651 QT_FT_Span spans[NSPANS];
2654 const int x1 = x0 + w;
2655 const int y1 = y0 + h;
2658 for (
int y = y0; y < y1; ++y) {
2659 for (
int x = x0; x < x1; ) {
2660 if (!monoVal(scanline, x)) {
2665 if (current == NSPANS) {
2666 blend(current, spans, &s->penData);
2669 spans[current].x = x + rx;
2670 spans[current].y = y + ry;
2671 spans[current].coverage = 255;
2675 while (x < x1 && monoVal(scanline, x)) {
2679 spans[current].len = len;
2684 }
else if (depth == 8) {
2685 for (
int y = y0; y < y1; ++y) {
2686 for (
int x = x0; x < x1; ) {
2688 if (scanline[x] == 0) {
2693 if (current == NSPANS) {
2694 blend(current, spans, &s->penData);
2697 int coverage = scanline[x];
2698 spans[current].x = x + rx;
2699 spans[current].y = y + ry;
2700 spans[current].coverage = coverage;
2705 while (x < x1 && scanline[x] == coverage) {
2709 spans[current].len = len;
2715 const uint *sl = (
const uint *) scanline;
2716 for (
int y = y0; y < y1; ++y) {
2717 for (
int x = x0; x < x1; ) {
2719 if ((sl[x] & 0x00ffffff) == 0) {
2724 if (current == NSPANS) {
2725 blend(current, spans, &s->penData);
2728 uint rgbCoverage = sl[x];
2729 int coverage = qGreen(rgbCoverage);
2730 spans[current].x = x + rx;
2731 spans[current].y = y + ry;
2732 spans[current].coverage = coverage;
2737 while (x < x1 && sl[x] == rgbCoverage) {
2741 spans[current].len = len;
2744 sl += bpl /
sizeof(uint);
2751 blend(current, spans, &s->penData);
2755
2756
2757bool QRasterPaintEngine::drawCachedGlyphs(
int numGlyphs,
const glyph_t *glyphs,
2758 const QFixedPoint *positions, QFontEngine *fontEngine)
2760 Q_D(QRasterPaintEngine);
2761 QRasterPaintEngineState *s = state();
2763 bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
2764 && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
2766 if (fontEngine->hasInternalCaching()) {
2767 QFontEngine::GlyphFormat neededFormat =
2768 painter()->device()->devType() == QInternal::Widget
2769 ? QFontEngine::Format_None
2770 : QFontEngine::Format_A8;
2772 if (d_func()->mono_surface)
2773 neededFormat = QFontEngine::Format_Mono;
2775 for (
int i = 0; i < numGlyphs; i++) {
2776 QFixedPoint spp = fontEngine->subPixelPositionFor(positions[i]);
2777 if (!verticalSubPixelPositions)
2780 const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
2786 switch (alphaMap->format) {
2787 case QFontEngine::Format_Mono:
2789 bytesPerLine = ((alphaMap->width + 31) & ~31) >> 3;
2791 case QFontEngine::Format_A8:
2793 bytesPerLine = (alphaMap->width + 3) & ~3;
2795 case QFontEngine::Format_A32:
2797 bytesPerLine = alphaMap->width * 4;
2803 QFixed y = verticalSubPixelPositions
2804 ? qFloor(positions[i].y)
2805 : qRound(positions[i].y);
2807 alphaPenBlt(alphaMap->data, bytesPerLine, depth,
2808 qFloor(positions[i].x) + alphaMap->x,
2809 qFloor(y) - alphaMap->y,
2810 alphaMap->width, alphaMap->height,
2811 fontEngine->expectsGammaCorrectedBlending());
2815 QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
2817 QImageTextureGlyphCache *cache =
2818 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(
nullptr, glyphFormat, s->matrix, s->penData.solidColor));
2820 cache =
new QImageTextureGlyphCache(glyphFormat, s->matrix, s->penData.solidColor);
2821 fontEngine->setGlyphCache(
nullptr, cache);
2824 cache->populate(fontEngine, numGlyphs, glyphs, positions, s->renderHints);
2825 cache->fillInPendingGlyphs();
2827 const QImage &image = cache->image();
2828 qsizetype bpl = image.bytesPerLine();
2830 int depth = image.depth();
2835 else if (depth == 1)
2838 int margin = fontEngine->glyphMargin(glyphFormat);
2839 const uchar *bits = image.bits();
2840 for (
int i=0; i<numGlyphs; ++i) {
2841 QFixedPoint subPixelPosition = fontEngine->subPixelPositionFor(positions[i]);
2842 if (!verticalSubPixelPositions)
2843 subPixelPosition.y = 0;
2845 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2846 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2850 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2851 int y = (verticalSubPixelPositions
2852 ? qFloor(positions[i].y)
2853 : qRound(positions[i].y));
2854 y -= c.baseLineY + margin;
2864 const uchar *glyphBits = bits + ((c.x << leftShift) >> rightShift) + c.y * bpl;
2866 if (glyphFormat == QFontEngine::Format_ARGB) {
2870 QTransform originalTransform = s->matrix;
2871 s->matrix = QTransform();
2872 drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format()));
2873 s->matrix = originalTransform;
2875 alphaPenBlt(glyphBits, bpl, depth, x, y, c.w, c.h, fontEngine->expectsGammaCorrectedBlending());
2884
2885
2886
2887
2893 const QRect &r1 = deviceRect;
2894 return (r.left() >= r1.left() && r.right() <= r1.right()
2895 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2901 if (cl->clipRect == deviceRect)
2905 const QRect &r1 = cl->clipRect;
2906 return (r.left() >= r1.left() && r.right() <= r1.right()
2907 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2909 return qt_region_strictContains(cl->clipRegion, r);
2916 Q_Q(
const QRasterPaintEngine);
2919 QRect r = rect.normalized();
2922 const QRect &r1 = deviceRect;
2923 return (r.left() >= r1.left() && r.right() <= r1.right()
2924 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2929 if (cl->hasRectClip && cl->clipRect == deviceRect)
2936 r.setX(r.x() - penWidth);
2937 r.setY(r.y() - penWidth);
2938 r.setWidth(r.width() + 2 * penWidth);
2939 r.setHeight(r.height() + 2 * penWidth);
2944 const QRect &r1 = cl->clipRect;
2945 return (r.left() >= r1.left() && r.right() <= r1.right()
2946 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2948 return qt_region_strictContains(cl->clipRegion, r);
2955 const QRectF norm = rect.normalized();
2956 if (norm.left() <= qreal(INT_MIN) || norm.top() <= qreal(INT_MIN)
2957 || norm.right() > qreal(INT_MAX) || norm.bottom() > qreal(INT_MAX)
2958 || norm.width() > qreal(INT_MAX) || norm.height() > qreal(INT_MAX))
2960 return isUnclipped(norm.toAlignedRect(), penWidth);
2965 const QSpanData *data)
const
2967 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2972 const QSpanData *data)
const
2974 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2979 const QSpanData *data)
const
2981 Q_Q(
const QRasterPaintEngine);
2984 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2987 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2997 glyph_t *glyphs, QFixedPoint *positions,
int numGlyphs)
2999 QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
3000 QFixed clipRight = QFixed::fromReal(clip.right() + 1);
3001 QFixed clipTop = QFixed::fromReal(clip.top() - 1);
3002 QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
3005 while (first < numGlyphs) {
3006 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
3007 QFixed left = metrics.x + positions[first].x;
3008 QFixed top = metrics.y + positions[first].y;
3009 QFixed right = left + metrics.width;
3010 QFixed bottom = top + metrics.height;
3011 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3015 int last = numGlyphs - 1;
3016 while (last > first) {
3017 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
3018 QFixed left = metrics.x + positions[last].x;
3019 QFixed top = metrics.y + positions[last].y;
3020 QFixed right = left + metrics.width;
3021 QFixed bottom = top + metrics.height;
3022 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3026 return {first, last + 1};
3030
3031
3032void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3034 if (textItem->numGlyphs == 0)
3038 ensureRasterState();
3040 QTransform matrix = state()->matrix;
3042 QFontEngine *fontEngine = textItem->fontEngine();
3043 if (shouldDrawCachedGlyphs(fontEngine, matrix)) {
3044 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3046 }
else if (matrix.type() < QTransform::TxProject) {
3048 QTransform invMat = matrix.inverted(&invertible);
3052 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3053 textItem->fontEngine(), textItem->glyphs,
3054 textItem->glyphPositions, textItem->numGlyphs);
3055 QStaticTextItem copy = *textItem;
3056 copy.glyphs += range.begin;
3057 copy.glyphPositions += range.begin;
3058 copy.numGlyphs = range.end - range.begin;
3059 QPaintEngineEx::drawStaticTextItem(©);
3061 QPaintEngineEx::drawStaticTextItem(textItem);
3066
3067
3068void QRasterPaintEngine::drawTextItem(
const QPointF &p,
const QTextItem &textItem)
3070 const QTextItemInt &ti =
static_cast<
const QTextItemInt &>(textItem);
3073 Q_D(QRasterPaintEngine);
3074 fprintf(stderr,
" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3075 p.x(), p.y(), QStringView(ti.chars, ti.num_chars).toLatin1().data(),
3076 d->glyphCacheFormat);
3079 if (ti.glyphs.numGlyphs == 0)
3082 ensureRasterState();
3084 QRasterPaintEngineState *s = state();
3085 QTransform matrix = s->matrix;
3087 if (shouldDrawCachedGlyphs(ti.fontEngine, matrix)) {
3088 QVarLengthArray<QFixedPoint> positions;
3089 QVarLengthArray<glyph_t> glyphs;
3091 matrix.translate(p.x(), p.y());
3092 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3094 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3095 }
else if (matrix.type() < QTransform::TxProject
3096 && ti.fontEngine->supportsTransformation(matrix)) {
3098 QTransform invMat = matrix.inverted(&invertible);
3102 QVarLengthArray<QFixedPoint> positions;
3103 QVarLengthArray<glyph_t> glyphs;
3105 ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3106 ti.flags, glyphs, positions);
3107 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3108 ti.fontEngine, glyphs.data(), positions.data(),
3111 if (range.begin >= range.end)
3114 QStaticTextItem staticTextItem;
3115 staticTextItem.color = s->pen.color();
3116 staticTextItem.font = s->font;
3117 staticTextItem.setFontEngine(ti.fontEngine);
3118 staticTextItem.numGlyphs = range.end - range.begin;
3119 staticTextItem.glyphs = glyphs.data() + range.begin;
3120 staticTextItem.glyphPositions = positions.data() + range.begin;
3121 QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3123 QPaintEngineEx::drawTextItem(p, ti);
3128
3129
3130void QRasterPaintEngine::drawPoints(
const QPointF *points,
int pointCount)
3132 Q_D(QRasterPaintEngine);
3133 QRasterPaintEngineState *s = state();
3136 if (!s->penData.blend)
3139 if (!s->flags.fast_pen) {
3140 QPaintEngineEx::drawPoints(points, pointCount);
3144 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3145 stroker.drawPoints(points, pointCount);
3149void QRasterPaintEngine::drawPoints(
const QPoint *points,
int pointCount)
3151 Q_D(QRasterPaintEngine);
3152 QRasterPaintEngineState *s = state();
3155 if (!s->penData.blend)
3158 if (!s->flags.fast_pen) {
3159 QPaintEngineEx::drawPoints(points, pointCount);
3163 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3164 stroker.drawPoints(points, pointCount);
3168
3169
3170void QRasterPaintEngine::drawLines(
const QLine *lines,
int lineCount)
3173 qDebug() <<
" - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3175 Q_D(QRasterPaintEngine);
3176 QRasterPaintEngineState *s = state();
3179 if (!s->penData.blend)
3182 if (s->flags.fast_pen) {
3183 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3184 for (
int i=0; i<lineCount; ++i) {
3185 const QLine &l = lines[i];
3186 stroker.drawLine(l.p1(), l.p2());
3189 QPaintEngineEx::drawLines(lines, lineCount);
3199 Q_Q(QRasterPaintEngine);
3202 const QPen &pen = s->lastPen;
3203 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3204 const QList<qreal> pattern = pen.dashPattern();
3206 qreal patternLength = 0;
3207 for (
int i = 0; i < pattern.size(); ++i)
3208 patternLength += pattern.at(i);
3210 if (patternLength <= 0)
3213 qreal length = line.length();
3214 Q_ASSERT(length > 0);
3215 if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
3216 rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
3220 while (length > 0) {
3221 const bool rasterize = *inDash;
3222 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3225 if (dash >= length) {
3226 dash = line.length();
3227 *dashOffset += dash / width;
3231 *inDash = !(*inDash);
3232 if (++*dashIndex >= pattern.size())
3239 if (rasterize && dash > 0)
3240 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3245
3246
3247void QRasterPaintEngine::drawLines(
const QLineF *lines,
int lineCount)
3250 qDebug() <<
" - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3252 Q_D(QRasterPaintEngine);
3253 QRasterPaintEngineState *s = state();
3256 if (!s->penData.blend)
3258 if (s->flags.fast_pen) {
3259 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3260 for (
int i=0; i<lineCount; ++i) {
3261 QLineF line = lines[i];
3262 stroker.drawLine(line.p1(), line.p2());
3265 QPaintEngineEx::drawLines(lines, lineCount);
3271
3272
3273void QRasterPaintEngine::drawEllipse(
const QRectF &rect)
3275 Q_D(QRasterPaintEngine);
3276 QRasterPaintEngineState *s = state();
3279 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3280 || (qpen_style(s->lastPen) == Qt::NoPen))
3281 && !s->flags.antialiased
3282 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3284 && s->matrix.type() <= QTransform::TxScale)
3287 const QRectF r = s->matrix.mapRect(rect);
3288 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3289 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3290 const QRect brect = QRect(
int(r.x()),
int(r.y()),
3294 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3295 &s->penData, &s->brushData);
3299 QPaintEngineEx::drawEllipse(rect);
3305
3306
3307void QRasterPaintEngine::setDC(HDC hdc) {
3308 Q_D(QRasterPaintEngine);
3313
3314
3315HDC QRasterPaintEngine::getDC()
const
3317 Q_D(
const QRasterPaintEngine);
3322
3323
3324void QRasterPaintEngine::releaseDC(HDC)
const
3331
3332
3333bool QRasterPaintEngine::requiresPretransformedGlyphPositions(QFontEngine *fontEngine,
const QTransform &m)
const
3336 if (shouldDrawCachedGlyphs(fontEngine, m))
3340 return QPaintEngineEx::requiresPretransformedGlyphPositions(fontEngine, m);
3344
3345
3346
3347bool QRasterPaintEngine::shouldDrawCachedGlyphs(QFontEngine *fontEngine,
const QTransform &m)
const
3350 if (m.type() >= QTransform::TxProject)
3358 if (!fontEngine->hasInternalCaching() && !fontEngine->supportsTransformation(m))
3361 if (fontEngine->supportsTransformation(m) && !fontEngine->isSmoothlyScalable)
3364 return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, m);
3368
3369
3370QPoint QRasterPaintEngine::coordinateOffset()
const
3372 return QPoint(0, 0);
3375void QRasterPaintEngine::drawBitmap(
const QPointF &pos,
const QImage &image, QSpanData *fg)
3380 Q_D(QRasterPaintEngine);
3382 Q_ASSERT(image.depth() == 1);
3384 const int spanCount = 512;
3385 QT_FT_Span spans[spanCount];
3389 int w = image.width();
3390 int h = image.height();
3391 int px = qRound(pos.x());
3392 int py = qRound(pos.y());
3393 int ymax = qMin(py + h, d->rasterBuffer->height());
3394 int ymin = qMax(py, 0);
3395 int xmax = qMin(px + w, d->rasterBuffer->width());
3396 int xmin = qMax(px, 0);
3398 int x_offset = xmin - px;
3400 QImage::Format format = image.format();
3401 for (
int y = ymin; y < ymax; ++y) {
3402 const uchar *src = image.scanLine(y - py);
3403 if (format == QImage::Format_MonoLSB) {
3404 for (
int x = 0; x < xmax - xmin; ++x) {
3405 int src_x = x + x_offset;
3406 uchar pixel = src[src_x >> 3];
3411 if (pixel & (0x1 << (src_x & 7))) {
3412 spans[n].x = xmin + x;
3414 spans[n].coverage = 255;
3416 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3420 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3423 if (n == spanCount) {
3424 fg->blend(n, spans, fg);
3430 for (
int x = 0; x < xmax - xmin; ++x) {
3431 int src_x = x + x_offset;
3432 uchar pixel = src[src_x >> 3];
3437 if (pixel & (0x80 >> (x & 7))) {
3438 spans[n].x = xmin + x;
3440 spans[n].coverage = 255;
3442 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3446 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3449 if (n == spanCount) {
3450 fg->blend(n, spans, fg);
3458 fg->blend(n, spans, fg);
3464
3465
3466
3467
3468
3469
3472
3473
3474
3475QRasterPaintEngine::ClipType QRasterPaintEngine::clipType()
const
3477 Q_D(
const QRasterPaintEngine);
3479 const QClipData *clip = d->clip();
3480 if (!clip || clip->hasRectClip)
3487
3488
3489
3490QRectF QRasterPaintEngine::clipBoundingRect()
const
3492 Q_D(
const QRasterPaintEngine);
3494 const QClipData *clip = d->clip();
3497 return d->deviceRect;
3499 if (clip->hasRectClip)
3500 return clip->clipRect;
3502 return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3507 Q_Q(QRasterPaintEngine);
3510 rasterizer->setAntialiased(s->flags.antialiased);
3512 QRect clipRect(deviceRect);
3520 clipRect = clipRect.intersected(r);
3521 blend = data->blend;
3523 blend = data->unclipped_blend;
3526 rasterizer->setClipRect(clipRect);
3527 rasterizer->initialize(blend, data);
3531 ProcessSpans callback,
3534 if (!callback || !outline)
3537 Q_Q(QRasterPaintEngine);
3541 initializeRasterizer(spanData);
3543 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3547 rasterizer->rasterize(outline, fillRule);
3551 rasterize(outline, callback, (
void *)spanData, rasterBuffer);
3560 return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3564 ProcessSpans callback,
3567 if (!callback || !outline)
3570 Q_Q(QRasterPaintEngine);
3574 rasterizer->setAntialiased(s->flags.antialiased);
3575 rasterizer->setClipRect(deviceRect);
3576 rasterizer->initialize(callback, userData);
3578 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3582 rasterizer->rasterize(outline, fillRule);
3590 int rasterPoolSize = MINIMUM_POOL_SIZE;
3591 Q_DECL_UNINITIALIZED uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3592 uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3593 uchar *rasterPoolOnHeap =
nullptr;
3595 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3597 void *data = userData;
3599 QT_FT_BBox clip_box = { deviceRect.x(),
3601 deviceRect.x() + deviceRect.width(),
3602 deviceRect.y() + deviceRect.height() };
3604 QT_FT_Raster_Params rasterParams;
3605 rasterParams.target =
nullptr;
3606 rasterParams.source = outline;
3607 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3608 rasterParams.gray_spans =
nullptr;
3609 rasterParams.black_spans =
nullptr;
3610 rasterParams.bit_test =
nullptr;
3611 rasterParams.bit_set =
nullptr;
3612 rasterParams.user = data;
3613 rasterParams.clip_box = clip_box;
3618 int rendered_spans = 0;
3622 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3623 rasterParams.gray_spans = callback;
3624 rasterParams.skip_spans = rendered_spans;
3625 error = QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_render(*grayRaster.data(), &rasterParams);
3629 rasterPoolSize *= 2;
3630 if (rasterPoolSize > 1024 * 1024) {
3631 qWarning(
"QPainter: Rasterization of primitive failed");
3635 rendered_spans += QT_MANGLE_NAMESPACE(q_gray_rendered_spans)(*grayRaster.data());
3637 free(rasterPoolOnHeap);
3638 rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3640 Q_CHECK_PTR(rasterPoolOnHeap);
3642 rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3644 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*grayRaster.data());
3645 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(grayRaster.data());
3646 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3652 free(rasterPoolOnHeap);
3657 Q_Q(QRasterPaintEngine);
3660 if (!s->clipEnabled)
3664 replayClipOperations();
3669 Q_Q(QRasterPaintEngine);
3672 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3673 && s->matrix.type() <= QTransform::TxShear;
3678 Q_Q(
const QRasterPaintEngine);
3681 return s->flags.fast_images
3682 && (mode == QPainter::CompositionMode_SourceOver
3683 || (mode == QPainter::CompositionMode_Source
3684 && !image.hasAlphaChannel()));
3689 Q_Q(
const QRasterPaintEngine);
3691 if (!(mode == QPainter::CompositionMode_Source
3692 || (mode == QPainter::CompositionMode_SourceOver
3693 && !image.hasAlphaChannel())))
3697 Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
3699 if (s->intOpacity != 256
3700 || image.depth() < 8
3701 || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
3702 && (!isPixelAligned(pt) || !isPixelAligned(sr))))
3705 QImage::Format dFormat = rasterBuffer->format;
3706 QImage::Format sFormat = image.format();
3708 if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
3709 dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
3710 return (dFormat == sFormat);
3715 Q_ASSERT(image.depth() == 1);
3717 const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3718 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3719 if (sourceImage.isNull() || dest.isNull())
3722 QRgb fg = qPremultiply(color.rgba());
3725 int height = sourceImage.height();
3726 int width = sourceImage.width();
3727 for (
int y=0; y<height; ++y) {
3728 const uchar *source = sourceImage.constScanLine(y);
3729 QRgb *target =
reinterpret_cast<QRgb *>(dest.scanLine(y));
3730 for (
int x=0; x < width; ++x)
3731 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3742 compositionMode = QPainter::CompositionMode_SourceOver;
3750 m_buffer = (uchar *)image->bits();
3753 bytes_per_pixel = image->depth()/8;
3754 bytes_per_line = image->bytesPerLine();
3756 format = image->format();
3757 colorSpace = image->colorSpace();
3758 if (image->depth() == 1 && image->colorTable().size() == 2) {
3760 const QList<QRgb> colorTable = image->colorTable();
3761 destColor0 = qPremultiply(colorTable[0]);
3762 destColor1 = qPremultiply(colorTable[1]);
3771 m_clipLines =
nullptr;
3796 m_clipLines = (ClipLine *)calloc(clipSpanHeight,
sizeof(ClipLine));
3798 Q_CHECK_PTR(m_clipLines);
3800 allocated = clipSpanHeight;
3803 if (hasRegionClip) {
3804 const auto rects = clipRegion.begin();
3805 const int numRects = clipRegion.rectCount();
3806 const int maxSpans = (ymax - ymin) * numRects;
3807 allocated = qMax(allocated, maxSpans);
3808 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3809 Q_CHECK_PTR(m_spans);
3812 int firstInBand = 0;
3813 while (firstInBand < numRects) {
3814 const int currMinY = rects[firstInBand].y();
3815 const int currMaxY = currMinY + rects[firstInBand].height();
3817 while (y < currMinY) {
3818 m_clipLines[y].spans =
nullptr;
3819 m_clipLines[y].count = 0;
3823 int lastInBand = firstInBand;
3824 while (lastInBand + 1 < numRects && rects[lastInBand+1].top() == y)
3827 while (y < currMaxY) {
3829 m_clipLines[y].spans = m_spans + count;
3830 m_clipLines[y].count = lastInBand - firstInBand + 1;
3832 for (
int r = firstInBand; r <= lastInBand; ++r) {
3833 const QRect &currRect = rects[r];
3834 QT_FT_Span *span = m_spans + count;
3835 span->x = currRect.x();
3836 span->len = currRect.width();
3838 span->coverage = 255;
3844 firstInBand = lastInBand + 1;
3847 Q_ASSERT(count <= allocated);
3849 while (y < clipSpanHeight) {
3850 m_clipLines[y].spans =
nullptr;
3851 m_clipLines[y].count = 0;
3858 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3859 Q_CHECK_PTR(m_spans);
3864 m_clipLines[y].spans =
nullptr;
3865 m_clipLines[y].count = 0;
3869 const int len = clipRect.width();
3871 QT_FT_Span *span = m_spans + count;
3875 span->coverage = 255;
3878 m_clipLines[y].spans = span;
3879 m_clipLines[y].count = 1;
3883 while (y < clipSpanHeight) {
3884 m_clipLines[y].spans =
nullptr;
3885 m_clipLines[y].count = 0;
3896 m_clipLines =
nullptr;
3911 ymin = m_spans[0].y;
3912 ymax = m_spans[count-1].y + 1;
3916 const int firstLeft = m_spans[0].x;
3917 const int firstRight = m_spans[0].x + m_spans[0].len;
3920 for (
int i = 0; i <
count; ++i) {
3921 QT_FT_Span_& span = m_spans[i];
3924 if (span.y != y + 1 && y != -1)
3927 m_clipLines[y].spans = &span;
3928 m_clipLines[y]
.count = 1;
3932 const int spanLeft = span.x;
3933 const int spanRight = spanLeft + span.len;
3935 if (spanLeft <
xmin)
3938 if (spanRight >
xmax)
3941 if (spanLeft != firstLeft || spanRight != firstRight)
3947 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3952
3953
3956 if (hasRectClip && rect == clipRect)
3965 xmax = rect.x() + rect.width();
3978
3979
3982 if (region.rectCount() == 1) {
3983 setClipRect(region.boundingRect());
3989 clipRegion = region;
3992 const QRect rect = region.boundingRect();
3994 xmax = rect.x() + rect.width();
3996 ymax = rect.y() + rect.height();
4007
4008
4009
4011 const QT_FT_Span *spans,
const QT_FT_Span *end,
4012 QT_FT_Span **outSpans,
int available)
4016 QT_FT_Span *out = *outSpans;
4018 const QT_FT_Span *clipSpans = clip->m_spans + *currentClip;
4019 const QT_FT_Span *clipEnd = clip->m_spans + clip
->count;
4021 while (available && spans < end ) {
4022 if (clipSpans >= clipEnd) {
4026 if (clipSpans->y > spans->y) {
4030 if (spans->y != clipSpans->y) {
4031 if (spans->y < clip
->count && clip->m_clipLines[spans->y].spans)
4032 clipSpans = clip->m_clipLines[spans->y].spans;
4037 Q_ASSERT(spans->y == clipSpans->y);
4040 int sx2 = sx1 + spans->len;
4041 int cx1 = clipSpans->x;
4042 int cx2 = cx1 + clipSpans->len;
4044 if (cx1 < sx1 && cx2 < sx1) {
4047 }
else if (sx1 < cx1 && sx2 < cx1) {
4051 int x = qMax(sx1, cx1);
4052 int len = qMin(sx2, cx2) - x;
4054 out->x = qMax(sx1, cx1);
4055 out->len = qMin(sx2, cx2) - out->x;
4057 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4069 *currentClip = clipSpans - clip->m_spans;
4076 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4078 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4080 const int NSPANS = 512;
4081 Q_DECL_UNINITIALIZED QT_FT_Span cspans[NSPANS];
4082 int currentClip = 0;
4083 const QT_FT_Span *end = spans + spanCount;
4084 while (spans < end) {
4085 QT_FT_Span *clipped = cspans;
4086 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4090 if (clipped - cspans)
4091 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4096
4097
4098
4099
4103 const int minx = clip.left();
4104 const int miny = clip.top();
4105 const int maxx = clip.right();
4106 const int maxy = clip.bottom();
4108 QT_FT_Span *end = spans + numSpans;
4109 while (spans < end) {
4110 if (spans->y >= miny)
4115 QT_FT_Span *s = spans;
4119 if (s->x > maxx || s->x + s->len <= minx) {
4125 s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
4128 s->len = qMin(s->len, (maxx - s->x + 1));
4140 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4141 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4143 Q_ASSERT(fillData->clip);
4144 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4146 QT_FT_Span *s =
const_cast<QT_FT_Span *>(spans);
4148 count = qt_intersect_spans(s, count,
4149 fillData->clip->clipRect);
4151 fillData->unclipped_blend(count, s, fillData);
4154static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData)
4163 switch (clipData->operation) {
4165 case Qt::IntersectClip:
4170 int currentClip = 0;
4171 const QT_FT_Span *end = spans + count;
4172 while (spans < end) {
4173 QT_FT_Span *newspans = newClip->m_spans + newClip
->count;
4174 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4175 &newspans, newClip->allocated - newClip->count);
4176 newClip
->count = newspans - newClip->m_spans;
4178 newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 *
sizeof(QT_FT_Span)));
4185 case Qt::ReplaceClip:
4186 clipData
->newClip->appendSpans(spans, count);
4198 inline CacheInfo(QGradientStops s,
int op, QGradient::InterpolationMode mode) :
4210 quint64 hash_val = 0;
4212 const QGradientStops stops = gradient.stops();
4213 for (
int i = 0; i < stops.size() && i <= 2; i++)
4214 hash_val += stops[i].second.rgba64();
4216 QMutexLocker lock(&mutex);
4217 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4219 if (it == cache.constEnd())
4220 return addCacheElement(hash_val, gradient, opacity);
4223 const auto &cache_info = it.value();
4224 if (cache_info->stops == stops && cache_info->opacity == opacity && cache_info->interpolationMode == gradient.interpolationMode())
4227 }
while (it != cache.constEnd() && it.key() == hash_val);
4229 return addCacheElement(hash_val, gradient, opacity);
4237 QRgba64 *colorTable,
4238 int size,
int opacity)
const;
4240 if (cache.size() == maxCacheSize()) {
4242 cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize())));
4244 auto cache_entry =
std::make_shared<
CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode());
4245 generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
4246 for (
int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
4247 cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32();
4248 return cache.insert(hash_val, std::move(cache_entry)).value();
4257 const QGradientStops stops = gradient.stops();
4258 int stopCount = stops.size();
4259 Q_ASSERT(stopCount > 0);
4261 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4263 if (stopCount == 2) {
4264 QRgba64 first_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4265 QRgba64 second_color = combineAlpha256(stops[1].second.rgba64(), opacity);
4267 qreal first_stop = stops[0].first;
4268 qreal second_stop = stops[1].first;
4270 if (second_stop < first_stop) {
4271 quint64 tmp = first_color;
4272 first_color = second_color;
4274 qSwap(first_stop, second_stop);
4277 if (colorInterpolation) {
4278 first_color = qPremultiply(first_color);
4279 second_color = qPremultiply(second_color);
4282 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4283 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4285 uint red_first = uint(first_color.red()) << 16;
4286 uint green_first = uint(first_color.green()) << 16;
4287 uint blue_first = uint(first_color.blue()) << 16;
4288 uint alpha_first = uint(first_color.alpha()) << 16;
4290 uint red_second = uint(second_color.red()) << 16;
4291 uint green_second = uint(second_color.green()) << 16;
4292 uint blue_second = uint(second_color.blue()) << 16;
4293 uint alpha_second = uint(second_color.alpha()) << 16;
4296 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4297 if (colorInterpolation)
4298 colorTable[i] = first_color;
4300 colorTable[i] = qPremultiply(first_color);
4303 if (i < second_index) {
4304 qreal reciprocal = qreal(1) / (second_index - first_index);
4306 int red_delta = qRound((qreal(red_second) - red_first) * reciprocal);
4307 int green_delta = qRound((qreal(green_second) - green_first) * reciprocal);
4308 int blue_delta = qRound((qreal(blue_second) - blue_first) * reciprocal);
4309 int alpha_delta = qRound((qreal(alpha_second) - alpha_first) * reciprocal);
4312 red_first += 1 << 15;
4313 green_first += 1 << 15;
4314 blue_first += 1 << 15;
4315 alpha_first += 1 << 15;
4317 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4318 red_first += red_delta;
4319 green_first += green_delta;
4320 blue_first += blue_delta;
4321 alpha_first += alpha_delta;
4323 const QRgba64 color = qRgba64(red_first >> 16, green_first >> 16, blue_first >> 16, alpha_first >> 16);
4325 if (colorInterpolation)
4326 colorTable[i] = color;
4328 colorTable[i] = qPremultiply(color);
4332 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4333 if (colorInterpolation)
4334 colorTable[i] = second_color;
4336 colorTable[i] = qPremultiply(second_color);
4342 QRgba64 current_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4343 if (stopCount == 1) {
4344 current_color = qPremultiply(current_color);
4345 for (
int i = 0; i < size; ++i)
4346 colorTable[i] = current_color;
4351 qreal begin_pos = stops[0].first;
4352 qreal end_pos = stops[stopCount-1].first;
4357 qreal incr = 1 / qreal(size);
4358 qreal dpos = 1.5 * incr;
4361 colorTable[pos++] = qPremultiply(current_color);
4362 while (dpos <= begin_pos) {
4363 colorTable[pos] = colorTable[pos - 1];
4368 int current_stop = 0;
4373 if (dpos < end_pos) {
4375 while (dpos > stops[current_stop+1].first)
4378 if (current_stop != 0)
4379 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4380 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4382 if (colorInterpolation) {
4383 current_color = qPremultiply(current_color);
4384 next_color = qPremultiply(next_color);
4387 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4388 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4389 t = (dpos - stops[current_stop].first) * c;
4393 Q_ASSERT(current_stop < stopCount);
4395 int dist = qRound(t);
4396 int idist = 256 - dist;
4398 if (colorInterpolation)
4399 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
4401 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
4406 if (dpos >= end_pos)
4412 while (dpos > stops[current_stop+skip+1].first)
4416 current_stop += skip;
4418 current_color = next_color;
4420 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4421 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4423 if (colorInterpolation) {
4425 current_color = qPremultiply(current_color);
4426 next_color = qPremultiply(next_color);
4429 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4430 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4431 t = (dpos - stops[current_stop].first) * c;
4438 current_color = qPremultiply(combineAlpha256(stops[stopCount - 1].second.rgba64(), opacity));
4439 while (pos < size - 1) {
4440 colorTable[pos] = current_color;
4445 colorTable[size - 1] = current_color;
4451void QSpanData::init(QRasterBuffer *rb,
const QRasterPaintEngine *pe)
4457 m11 = m22 = m33 = 1.;
4458 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4459 clip = pe ? pe->d_func()->clip() :
nullptr;
4462Q_GUI_EXPORT
extern QImage qt_imageForBrush(
int brushStyle,
bool invert);
4464void QSpanData::setup(
const QBrush &brush,
int alpha, QPainter::CompositionMode compositionMode,
4467 Qt::BrushStyle brushStyle = qbrush_style(brush);
4468 cachedGradient.reset();
4469 switch (brushStyle) {
4470 case Qt::SolidPattern: {
4472 QColor c = qbrush_color(brush);
4473 solidColor = qPremultiplyWithExtraAlpha(c, alpha);
4474 if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
4479 case Qt::LinearGradientPattern:
4481 type = LinearGradient;
4482 const QLinearGradient *g =
static_cast<
const QLinearGradient *>(brush.gradient());
4483 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4485 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4486 gradient.colorTable32 = cacheInfo->buffer32;
4487#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4488 gradient.colorTable64 = cacheInfo->buffer64;
4490 cachedGradient = std::move(cacheInfo);
4492 gradient.spread = g->spread();
4494 QLinearGradientData &linearData = gradient.linear;
4496 linearData.origin.x = g->start().x();
4497 linearData.origin.y = g->start().y();
4498 linearData.end.x = g->finalStop().x();
4499 linearData.end.y = g->finalStop().y();
4503 case Qt::RadialGradientPattern:
4505 type = RadialGradient;
4506 const QRadialGradient *g =
static_cast<
const QRadialGradient *>(brush.gradient());
4507 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4509 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4510 gradient.colorTable32 = cacheInfo->buffer32;
4511#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4512 gradient.colorTable64 = cacheInfo->buffer64;
4514 cachedGradient = std::move(cacheInfo);
4516 gradient.spread = g->spread();
4518 QRadialGradientData &radialData = gradient.radial;
4520 QPointF center = g->center();
4521 radialData.center.x = center.x();
4522 radialData.center.y = center.y();
4523 radialData.center.radius = g->centerRadius();
4524 QPointF focal = g->focalPoint();
4525 radialData.focal.x = focal.x();
4526 radialData.focal.y = focal.y();
4527 radialData.focal.radius = g->focalRadius();
4531 case Qt::ConicalGradientPattern:
4533 type = ConicalGradient;
4534 const QConicalGradient *g =
static_cast<
const QConicalGradient *>(brush.gradient());
4535 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4537 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4538 gradient.colorTable32 = cacheInfo->buffer32;
4539#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4540 gradient.colorTable64 = cacheInfo->buffer64;
4542 cachedGradient = std::move(cacheInfo);
4544 gradient.spread = QGradient::RepeatSpread;
4546 QConicalGradientData &conicalData = gradient.conical;
4548 QPointF center = g->center();
4549 conicalData.center.x = center.x();
4550 conicalData.center.y = center.y();
4551 conicalData.angle = qDegreesToRadians(g->angle());
4555 case Qt::Dense1Pattern:
4556 case Qt::Dense2Pattern:
4557 case Qt::Dense3Pattern:
4558 case Qt::Dense4Pattern:
4559 case Qt::Dense5Pattern:
4560 case Qt::Dense6Pattern:
4561 case Qt::Dense7Pattern:
4562 case Qt::HorPattern:
4563 case Qt::VerPattern:
4564 case Qt::CrossPattern:
4565 case Qt::BDiagPattern:
4566 case Qt::FDiagPattern:
4567 case Qt::DiagCrossPattern:
4570 tempImage =
new QImage();
4571 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle,
true), brush.color());
4572 initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
4574 case Qt::TexturePattern:
4577 tempImage =
new QImage();
4579 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4580 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4582 *tempImage = brush.textureImage();
4583 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4591 adjustSpanMethods();
4594void QSpanData::adjustSpanMethods()
4596 bitmapBlit =
nullptr;
4597 alphamapBlit =
nullptr;
4598 alphaRGBBlit =
nullptr;
4604 unclipped_blend =
nullptr;
4607 const DrawHelper &drawHelper = qDrawHelper[rasterBuffer->format];
4608 unclipped_blend = drawHelper.blendColor;
4609 bitmapBlit = drawHelper.bitmapBlit;
4610 alphamapBlit = drawHelper.alphamapBlit;
4611 alphaRGBBlit = drawHelper.alphaRGBBlit;
4612 fillRect = drawHelper.fillRect;
4615 case LinearGradient:
4616 case RadialGradient:
4617 case ConicalGradient:
4618 unclipped_blend = qBlendGradient;
4621 unclipped_blend = qBlendTexture;
4622 if (!texture.imageData)
4623 unclipped_blend =
nullptr;
4628 if (!unclipped_blend) {
4631 blend = unclipped_blend;
4632 }
else if (clip->hasRectClip) {
4633 blend = clip->clipRect.isEmpty() ?
nullptr : qt_span_fill_clipRect;
4635 blend = qt_span_fill_clipped;
4639void QSpanData::setupMatrix(
const QTransform &matrix,
int bilin)
4643 delta.translate(1.0 / 65536, 1.0 / 65536);
4645 QTransform inv = (delta * matrix).inverted();
4658 const bool affine = inv.isAffine();
4659 const qreal f1 = m11 * m11 + m21 * m21;
4660 const qreal f2 = m12 * m12 + m22 * m22;
4661 fast_matrix = affine
4664 && f1 > (1.0 / 65536)
4665 && f2 > (1.0 / 65536)
4669 adjustSpanMethods();
4672void QSpanData::initTexture(
const QImage *image,
int alpha, QTextureData::Type _type,
const QRect &sourceRect)
4674 const QImageData *d =
const_cast<QImage *>(image)->data_ptr();
4675 if (!d || d->height == 0) {
4676 texture.imageData =
nullptr;
4683 texture.bytesPerLine = 0;
4684 texture.format = QImage::Format_Invalid;
4685 texture.colorTable =
nullptr;
4686 texture.hasAlpha = alpha != 256;
4688 texture.imageData = d->data;
4689 texture.width = d->width;
4690 texture.height = d->height;
4692 if (sourceRect.isNull()) {
4695 texture.x2 = texture.width;
4696 texture.y2 = texture.height;
4698 texture.x1 = sourceRect.x();
4699 texture.y1 = sourceRect.y();
4700 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4701 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4704 texture.bytesPerLine = d->bytes_per_line;
4706 texture.format = d->format;
4707 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable :
nullptr;
4708 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4710 texture.const_alpha = alpha;
4711 texture.type = _type;
4713 adjustSpanMethods();
4717
4718
4719
4723 ProcessSpans pen_func, ProcessSpans brush_func,
4724 QSpanData *pen_data, QSpanData *brush_data)
4729 QT_FT_Span _outline[4];
4730 QT_FT_Span *outline = _outline;
4731 const int midx = rect.x() + (rect.width() + 1) / 2;
4732 const int midy = rect.y() + (rect.height() + 1) / 2;
4738 outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4739 outline[0].len = qMin(length, x - outline[0].x);
4741 outline[0].coverage = 255;
4745 outline[1].len = length;
4747 outline[1].coverage = 255;
4750 outline[2].x = outline[0].x;
4751 outline[2].len = outline[0].len;
4752 outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4753 outline[2].coverage = 255;
4757 outline[3].len = length;
4758 outline[3].y = outline[2].y;
4759 outline[3].coverage = 255;
4761 if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4762 QT_FT_Span _fill[2];
4763 QT_FT_Span *fill = _fill;
4766 fill[0].x = outline[0].x + outline[0].len - 1;
4767 fill[0].len = qMax(0, outline[1].x - fill[0].x);
4768 fill[0].y = outline[1].y;
4769 fill[0].coverage = 255;
4772 fill[1].x = outline[2].x + outline[2].len - 1;
4773 fill[1].len = qMax(0, outline[3].x - fill[1].x);
4774 fill[1].y = outline[3].y;
4775 fill[1].coverage = 255;
4777 int n = (fill[0].y >= fill[1].y ? 1 : 2);
4778 n = qt_intersect_spans(fill, n, clip);
4780 brush_func(n, fill, brush_data);
4783 int n = (outline[1].y >= outline[2].y ? 2 : 4);
4784 n = qt_intersect_spans(outline, n, clip);
4786 pen_func(n, outline, pen_data);
4791
4792
4793
4795 ProcessSpans pen_func, ProcessSpans brush_func,
4796 QSpanData *pen_data, QSpanData *brush_data)
4798 const qreal a = qreal(rect.width()) / 2;
4799 const qreal b = qreal(rect.height()) / 2;
4800 qreal d = b*b - (a*a*b) + 0.25*a*a;
4803 int y = (rect.height() + 1) / 2;
4807 while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4812 d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4813 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4814 pen_func, brush_func, pen_data, brush_data);
4819 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4820 pen_func, brush_func, pen_data, brush_data);
4823 d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4824 const int miny = rect.height() & 0x1;
4827 d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4830 d += a*a*(-2*y + 3);
4833 drawEllipsePoints(x, y, 1, rect, clip,
4834 pen_func, brush_func, pen_data, brush_data);
4839
4840
4841
4842
4846void dumpClip(
int width,
int height,
const QClipData *clip)
4848 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4849 clipImg.fill(0xffff0000);
4856 ((QClipData *) clip)->spans();
4858 for (
int i = 0; i < clip->count; ++i) {
4859 const QT_FT_Span *span = ((QClipData *) clip)->spans() + i;
4860 for (
int j = 0; j < span->len; ++j)
4861 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4862 x0 = qMin(x0,
int(span->x));
4863 x1 = qMax(x1,
int(span->x + span->len - 1));
4865 y0 = qMin(y0,
int(span->y));
4866 y1 = qMax(y1,
int(span->y));
4869 static int counter = 0;
4876 fprintf(stderr,
"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4877 clipImg.save(QString::fromLatin1(
"clip-%0.png").arg(counter++));
void setClipRegion(const QRegion ®ion)
void setClipRect(const QRect &rect)
void generateGradientColorTable(const QGradient &g, QRgba64 *colorTable, int size, int opacity) const
QGradientColorTableHash cache
std::shared_ptr< const CacheInfo > addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity)
std::shared_ptr< const CacheInfo > getBuffer(const QGradient &gradient, int opacity)
bool monoDestinationWithClut
QImage::Format prepare(QImage *image)
QImage colorizeBitmap(const QImage &image, const QColor &color)
bool isUnclipped_normalized(const QRect &rect) const
void recalculateFastImages()
void initializeRasterizer(QSpanData *data)
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *rasterBuffer)
bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const
bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, const QRect &clip, int alpha, const QRect &sr=QRect())
bool isUnclipped(const QRect &rect, int penWidth) const
void rasterizeLine_dashed(QLineF line, qreal width, int *dashIndex, qreal *dashOffset, bool *inDash)
void blitImage(const QPointF &pt, const QImage &img, const QRect &clip, const QRect &sr=QRect())
const QClipData * clip() const
void systemStateChanged() override
void updateMatrixData(QSpanData *spanData, const QBrush &brush, const QTransform &brushMatrix)
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, QSpanData *spanData, QRasterBuffer *rasterBuffer)
ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const
~QRasterPaintEngineState()
QRasterPaintEngineState(const QRasterPaintEngineState &other)
QRasterPaintEngineState()
QRectVectorPath(const QRect &r)
Combined button and popup list for selecting options.
void QT_MANGLE_NAMESPACE qt_startup_hook()
QT_BEGIN_NAMESPACE constexpr int QT_RASTER_COORD_LIMIT
@ LineDrawIncludeLastPixel
static int fast_ceil_positive(const qreal &v)
static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans, void *userData)
static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data)
static void fillRect_normalized(const QRect &r, QSpanData *data, QRasterPaintEnginePrivate *pe)
static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
static const QT_FT_Span * qt_intersect_spans(const QClipData *clip, int *currentClip, const QT_FT_Span *spans, const QT_FT_Span *end, QT_FT_Span **outSpans, int available)
QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData)
static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
static VisibleGlyphRange visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
static bool monoVal(const uchar *s, int x)
static uchar * alignAddress(uchar *address, quintptr alignmentMask)
static bool splitPolygon(const QPointF *points, int pointCount, QList< QPointF > *upper, QList< QPointF > *lower)
static void drawEllipsePoints(int x, int y, int length, const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data)
static void qt_span_fill_clipped(int count, const QT_FT_Span *spans, void *userData)
static QColor qPremultiplyWithExtraAlpha(const QColor &c, int alpha)
static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)
#define int_dim(pos, dim)
static const QRect toAlignedRect_positive(const QRectF &rect)
static bool isAbove(const QPointF *a, const QPointF *b)
static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans, const QRect &clip)
Qt::ClipOperation operation
QRgba64 buffer64[GRADIENT_STOPTABLE_SIZE]
QRgb buffer32[GRADIENT_STOPTABLE_SIZE]
CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode)
QGradient::InterpolationMode interpolationMode