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
2892 const QRect &r1 = deviceRect;
2893 return (r.left() >= r1.left() && r.right() <= r1.right()
2894 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2900 if (cl->clipRect == deviceRect)
2904 const QRect &r1 = cl->clipRect;
2905 return (r.left() >= r1.left() && r.right() <= r1.right()
2906 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2908 return qt_region_strictContains(cl->clipRegion, r);
2915 Q_Q(
const QRasterPaintEngine);
2918 QRect r = rect.normalized();
2921 const QRect &r1 = deviceRect;
2922 return (r.left() >= r1.left() && r.right() <= r1.right()
2923 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2928 if (cl->hasRectClip && cl->clipRect == deviceRect)
2935 r.setX(r.x() - penWidth);
2936 r.setY(r.y() - penWidth);
2937 r.setWidth(r.width() + 2 * penWidth);
2938 r.setHeight(r.height() + 2 * penWidth);
2943 const QRect &r1 = cl->clipRect;
2944 return (r.left() >= r1.left() && r.right() <= r1.right()
2945 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2947 return qt_region_strictContains(cl->clipRegion, r);
2954 const QRectF norm = rect.normalized();
2955 if (norm.left() <= INT_MIN || norm.top() <= INT_MIN
2956 || norm.right() > INT_MAX || norm.bottom() > INT_MAX
2957 || norm.width() > INT_MAX || norm.height() > INT_MAX)
2959 return isUnclipped(norm.toAlignedRect(), penWidth);
2964 const QSpanData *data)
const
2966 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2971 const QSpanData *data)
const
2973 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2978 const QSpanData *data)
const
2980 Q_Q(
const QRasterPaintEngine);
2983 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2986 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2996 glyph_t *glyphs, QFixedPoint *positions,
int numGlyphs)
2998 QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
2999 QFixed clipRight = QFixed::fromReal(clip.right() + 1);
3000 QFixed clipTop = QFixed::fromReal(clip.top() - 1);
3001 QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
3004 while (first < numGlyphs) {
3005 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
3006 QFixed left = metrics.x + positions[first].x;
3007 QFixed top = metrics.y + positions[first].y;
3008 QFixed right = left + metrics.width;
3009 QFixed bottom = top + metrics.height;
3010 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3014 int last = numGlyphs - 1;
3015 while (last > first) {
3016 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
3017 QFixed left = metrics.x + positions[last].x;
3018 QFixed top = metrics.y + positions[last].y;
3019 QFixed right = left + metrics.width;
3020 QFixed bottom = top + metrics.height;
3021 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3025 return {first, last + 1};
3029
3030
3031void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3033 if (textItem->numGlyphs == 0)
3037 ensureRasterState();
3039 QTransform matrix = state()->matrix;
3041 QFontEngine *fontEngine = textItem->fontEngine();
3042 if (shouldDrawCachedGlyphs(fontEngine, matrix)) {
3043 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3045 }
else if (matrix.type() < QTransform::TxProject) {
3047 QTransform invMat = matrix.inverted(&invertible);
3051 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3052 textItem->fontEngine(), textItem->glyphs,
3053 textItem->glyphPositions, textItem->numGlyphs);
3054 QStaticTextItem copy = *textItem;
3055 copy.glyphs += range.begin;
3056 copy.glyphPositions += range.begin;
3057 copy.numGlyphs = range.end - range.begin;
3058 QPaintEngineEx::drawStaticTextItem(©);
3060 QPaintEngineEx::drawStaticTextItem(textItem);
3065
3066
3067void QRasterPaintEngine::drawTextItem(
const QPointF &p,
const QTextItem &textItem)
3069 const QTextItemInt &ti =
static_cast<
const QTextItemInt &>(textItem);
3072 Q_D(QRasterPaintEngine);
3073 fprintf(stderr,
" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3074 p.x(), p.y(), QStringView(ti.chars, ti.num_chars).toLatin1().data(),
3075 d->glyphCacheFormat);
3078 if (ti.glyphs.numGlyphs == 0)
3081 ensureRasterState();
3083 QRasterPaintEngineState *s = state();
3084 QTransform matrix = s->matrix;
3086 if (shouldDrawCachedGlyphs(ti.fontEngine, matrix)) {
3087 QVarLengthArray<QFixedPoint> positions;
3088 QVarLengthArray<glyph_t> glyphs;
3090 matrix.translate(p.x(), p.y());
3091 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3093 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3094 }
else if (matrix.type() < QTransform::TxProject
3095 && ti.fontEngine->supportsTransformation(matrix)) {
3097 QTransform invMat = matrix.inverted(&invertible);
3101 QVarLengthArray<QFixedPoint> positions;
3102 QVarLengthArray<glyph_t> glyphs;
3104 ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3105 ti.flags, glyphs, positions);
3106 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3107 ti.fontEngine, glyphs.data(), positions.data(),
3110 if (range.begin >= range.end)
3113 QStaticTextItem staticTextItem;
3114 staticTextItem.color = s->pen.color();
3115 staticTextItem.font = s->font;
3116 staticTextItem.setFontEngine(ti.fontEngine);
3117 staticTextItem.numGlyphs = range.end - range.begin;
3118 staticTextItem.glyphs = glyphs.data() + range.begin;
3119 staticTextItem.glyphPositions = positions.data() + range.begin;
3120 QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3122 QPaintEngineEx::drawTextItem(p, ti);
3127
3128
3129void QRasterPaintEngine::drawPoints(
const QPointF *points,
int pointCount)
3131 Q_D(QRasterPaintEngine);
3132 QRasterPaintEngineState *s = state();
3135 if (!s->penData.blend)
3138 if (!s->flags.fast_pen) {
3139 QPaintEngineEx::drawPoints(points, pointCount);
3143 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3144 stroker.drawPoints(points, pointCount);
3148void QRasterPaintEngine::drawPoints(
const QPoint *points,
int pointCount)
3150 Q_D(QRasterPaintEngine);
3151 QRasterPaintEngineState *s = state();
3154 if (!s->penData.blend)
3157 if (!s->flags.fast_pen) {
3158 QPaintEngineEx::drawPoints(points, pointCount);
3162 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3163 stroker.drawPoints(points, pointCount);
3167
3168
3169void QRasterPaintEngine::drawLines(
const QLine *lines,
int lineCount)
3172 qDebug() <<
" - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3174 Q_D(QRasterPaintEngine);
3175 QRasterPaintEngineState *s = state();
3178 if (!s->penData.blend)
3181 if (s->flags.fast_pen) {
3182 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3183 for (
int i=0; i<lineCount; ++i) {
3184 const QLine &l = lines[i];
3185 stroker.drawLine(l.p1(), l.p2());
3188 QPaintEngineEx::drawLines(lines, lineCount);
3198 Q_Q(QRasterPaintEngine);
3201 const QPen &pen = s->lastPen;
3202 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3203 const QList<qreal> pattern = pen.dashPattern();
3205 qreal patternLength = 0;
3206 for (
int i = 0; i < pattern.size(); ++i)
3207 patternLength += pattern.at(i);
3209 if (patternLength <= 0)
3212 qreal length = line.length();
3213 Q_ASSERT(length > 0);
3214 if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
3215 rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
3219 while (length > 0) {
3220 const bool rasterize = *inDash;
3221 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3224 if (dash >= length) {
3225 dash = line.length();
3226 *dashOffset += dash / width;
3230 *inDash = !(*inDash);
3231 if (++*dashIndex >= pattern.size())
3238 if (rasterize && dash > 0)
3239 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3244
3245
3246void QRasterPaintEngine::drawLines(
const QLineF *lines,
int lineCount)
3249 qDebug() <<
" - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3251 Q_D(QRasterPaintEngine);
3252 QRasterPaintEngineState *s = state();
3255 if (!s->penData.blend)
3257 if (s->flags.fast_pen) {
3258 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3259 for (
int i=0; i<lineCount; ++i) {
3260 QLineF line = lines[i];
3261 stroker.drawLine(line.p1(), line.p2());
3264 QPaintEngineEx::drawLines(lines, lineCount);
3270
3271
3272void QRasterPaintEngine::drawEllipse(
const QRectF &rect)
3274 Q_D(QRasterPaintEngine);
3275 QRasterPaintEngineState *s = state();
3278 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3279 || (qpen_style(s->lastPen) == Qt::NoPen))
3280 && !s->flags.antialiased
3281 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3283 && s->matrix.type() <= QTransform::TxScale)
3286 const QRectF r = s->matrix.mapRect(rect);
3287 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3288 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3289 const QRect brect = QRect(
int(r.x()),
int(r.y()),
3293 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3294 &s->penData, &s->brushData);
3298 QPaintEngineEx::drawEllipse(rect);
3304
3305
3306void QRasterPaintEngine::setDC(HDC hdc) {
3307 Q_D(QRasterPaintEngine);
3312
3313
3314HDC QRasterPaintEngine::getDC()
const
3316 Q_D(
const QRasterPaintEngine);
3321
3322
3323void QRasterPaintEngine::releaseDC(HDC)
const
3330
3331
3332bool QRasterPaintEngine::requiresPretransformedGlyphPositions(QFontEngine *fontEngine,
const QTransform &m)
const
3335 if (shouldDrawCachedGlyphs(fontEngine, m))
3339 return QPaintEngineEx::requiresPretransformedGlyphPositions(fontEngine, m);
3343
3344
3345
3346bool QRasterPaintEngine::shouldDrawCachedGlyphs(QFontEngine *fontEngine,
const QTransform &m)
const
3349 if (m.type() >= QTransform::TxProject)
3357 if (!fontEngine->hasInternalCaching() && !fontEngine->supportsTransformation(m))
3360 if (fontEngine->supportsTransformation(m) && !fontEngine->isSmoothlyScalable)
3363 return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, m);
3367
3368
3369QPoint QRasterPaintEngine::coordinateOffset()
const
3371 return QPoint(0, 0);
3374void QRasterPaintEngine::drawBitmap(
const QPointF &pos,
const QImage &image, QSpanData *fg)
3379 Q_D(QRasterPaintEngine);
3381 Q_ASSERT(image.depth() == 1);
3383 const int spanCount = 512;
3384 QT_FT_Span spans[spanCount];
3388 int w = image.width();
3389 int h = image.height();
3390 int px = qRound(pos.x());
3391 int py = qRound(pos.y());
3392 int ymax = qMin(py + h, d->rasterBuffer->height());
3393 int ymin = qMax(py, 0);
3394 int xmax = qMin(px + w, d->rasterBuffer->width());
3395 int xmin = qMax(px, 0);
3397 int x_offset = xmin - px;
3399 QImage::Format format = image.format();
3400 for (
int y = ymin; y < ymax; ++y) {
3401 const uchar *src = image.scanLine(y - py);
3402 if (format == QImage::Format_MonoLSB) {
3403 for (
int x = 0; x < xmax - xmin; ++x) {
3404 int src_x = x + x_offset;
3405 uchar pixel = src[src_x >> 3];
3410 if (pixel & (0x1 << (src_x & 7))) {
3411 spans[n].x = xmin + x;
3413 spans[n].coverage = 255;
3415 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3419 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3422 if (n == spanCount) {
3423 fg->blend(n, spans, fg);
3429 for (
int x = 0; x < xmax - xmin; ++x) {
3430 int src_x = x + x_offset;
3431 uchar pixel = src[src_x >> 3];
3436 if (pixel & (0x80 >> (x & 7))) {
3437 spans[n].x = xmin + x;
3439 spans[n].coverage = 255;
3441 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3445 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3448 if (n == spanCount) {
3449 fg->blend(n, spans, fg);
3457 fg->blend(n, spans, fg);
3463
3464
3465
3466
3467
3468
3471
3472
3473
3474QRasterPaintEngine::ClipType QRasterPaintEngine::clipType()
const
3476 Q_D(
const QRasterPaintEngine);
3478 const QClipData *clip = d->clip();
3479 if (!clip || clip->hasRectClip)
3486
3487
3488
3489QRectF QRasterPaintEngine::clipBoundingRect()
const
3491 Q_D(
const QRasterPaintEngine);
3493 const QClipData *clip = d->clip();
3496 return d->deviceRect;
3498 if (clip->hasRectClip)
3499 return clip->clipRect;
3501 return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3506 Q_Q(QRasterPaintEngine);
3509 rasterizer->setAntialiased(s->flags.antialiased);
3511 QRect clipRect(deviceRect);
3519 clipRect = clipRect.intersected(r);
3520 blend = data->blend;
3522 blend = data->unclipped_blend;
3525 rasterizer->setClipRect(clipRect);
3526 rasterizer->initialize(blend, data);
3530 ProcessSpans callback,
3533 if (!callback || !outline)
3536 Q_Q(QRasterPaintEngine);
3540 initializeRasterizer(spanData);
3542 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3546 rasterizer->rasterize(outline, fillRule);
3550 rasterize(outline, callback, (
void *)spanData, rasterBuffer);
3559 return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3563 ProcessSpans callback,
3566 if (!callback || !outline)
3569 Q_Q(QRasterPaintEngine);
3573 rasterizer->setAntialiased(s->flags.antialiased);
3574 rasterizer->setClipRect(deviceRect);
3575 rasterizer->initialize(callback, userData);
3577 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3581 rasterizer->rasterize(outline, fillRule);
3589 int rasterPoolSize = MINIMUM_POOL_SIZE;
3590 Q_DECL_UNINITIALIZED uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3591 uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3592 uchar *rasterPoolOnHeap =
nullptr;
3594 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3596 void *data = userData;
3598 QT_FT_BBox clip_box = { deviceRect.x(),
3600 deviceRect.x() + deviceRect.width(),
3601 deviceRect.y() + deviceRect.height() };
3603 QT_FT_Raster_Params rasterParams;
3604 rasterParams.target =
nullptr;
3605 rasterParams.source = outline;
3606 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3607 rasterParams.gray_spans =
nullptr;
3608 rasterParams.black_spans =
nullptr;
3609 rasterParams.bit_test =
nullptr;
3610 rasterParams.bit_set =
nullptr;
3611 rasterParams.user = data;
3612 rasterParams.clip_box = clip_box;
3617 int rendered_spans = 0;
3621 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3622 rasterParams.gray_spans = callback;
3623 rasterParams.skip_spans = rendered_spans;
3624 error = QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_render(*grayRaster.data(), &rasterParams);
3628 rasterPoolSize *= 2;
3629 if (rasterPoolSize > 1024 * 1024) {
3630 qWarning(
"QPainter: Rasterization of primitive failed");
3634 rendered_spans += QT_MANGLE_NAMESPACE(q_gray_rendered_spans)(*grayRaster.data());
3636 free(rasterPoolOnHeap);
3637 rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3639 Q_CHECK_PTR(rasterPoolOnHeap);
3641 rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3643 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*grayRaster.data());
3644 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(grayRaster.data());
3645 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3651 free(rasterPoolOnHeap);
3656 Q_Q(QRasterPaintEngine);
3659 if (!s->clipEnabled)
3663 replayClipOperations();
3668 Q_Q(QRasterPaintEngine);
3671 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3672 && s->matrix.type() <= QTransform::TxShear;
3677 Q_Q(
const QRasterPaintEngine);
3680 return s->flags.fast_images
3681 && (mode == QPainter::CompositionMode_SourceOver
3682 || (mode == QPainter::CompositionMode_Source
3683 && !image.hasAlphaChannel()));
3688 Q_Q(
const QRasterPaintEngine);
3690 if (!(mode == QPainter::CompositionMode_Source
3691 || (mode == QPainter::CompositionMode_SourceOver
3692 && !image.hasAlphaChannel())))
3696 Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
3698 if (s->intOpacity != 256
3699 || image.depth() < 8
3700 || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
3701 && (!isPixelAligned(pt) || !isPixelAligned(sr))))
3704 QImage::Format dFormat = rasterBuffer->format;
3705 QImage::Format sFormat = image.format();
3707 if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
3708 dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
3709 return (dFormat == sFormat);
3714 Q_ASSERT(image.depth() == 1);
3716 const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3717 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3718 if (sourceImage.isNull() || dest.isNull())
3721 QRgb fg = qPremultiply(color.rgba());
3724 int height = sourceImage.height();
3725 int width = sourceImage.width();
3726 for (
int y=0; y<height; ++y) {
3727 const uchar *source = sourceImage.constScanLine(y);
3728 QRgb *target =
reinterpret_cast<QRgb *>(dest.scanLine(y));
3729 for (
int x=0; x < width; ++x)
3730 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3741 compositionMode = QPainter::CompositionMode_SourceOver;
3749 m_buffer = (uchar *)image->bits();
3752 bytes_per_pixel = image->depth()/8;
3753 bytes_per_line = image->bytesPerLine();
3755 format = image->format();
3756 colorSpace = image->colorSpace();
3757 if (image->depth() == 1 && image->colorTable().size() == 2) {
3759 const QList<QRgb> colorTable = image->colorTable();
3760 destColor0 = qPremultiply(colorTable[0]);
3761 destColor1 = qPremultiply(colorTable[1]);
3770 m_clipLines =
nullptr;
3795 m_clipLines = (ClipLine *)calloc(clipSpanHeight,
sizeof(ClipLine));
3797 Q_CHECK_PTR(m_clipLines);
3799 allocated = clipSpanHeight;
3802 if (hasRegionClip) {
3803 const auto rects = clipRegion.begin();
3804 const int numRects = clipRegion.rectCount();
3805 const int maxSpans = (ymax - ymin) * numRects;
3806 allocated = qMax(allocated, maxSpans);
3807 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3808 Q_CHECK_PTR(m_spans);
3811 int firstInBand = 0;
3812 while (firstInBand < numRects) {
3813 const int currMinY = rects[firstInBand].y();
3814 const int currMaxY = currMinY + rects[firstInBand].height();
3816 while (y < currMinY) {
3817 m_clipLines[y].spans =
nullptr;
3818 m_clipLines[y].count = 0;
3822 int lastInBand = firstInBand;
3823 while (lastInBand + 1 < numRects && rects[lastInBand+1].top() == y)
3826 while (y < currMaxY) {
3828 m_clipLines[y].spans = m_spans + count;
3829 m_clipLines[y].count = lastInBand - firstInBand + 1;
3831 for (
int r = firstInBand; r <= lastInBand; ++r) {
3832 const QRect &currRect = rects[r];
3833 QT_FT_Span *span = m_spans + count;
3834 span->x = currRect.x();
3835 span->len = currRect.width();
3837 span->coverage = 255;
3843 firstInBand = lastInBand + 1;
3846 Q_ASSERT(count <= allocated);
3848 while (y < clipSpanHeight) {
3849 m_clipLines[y].spans =
nullptr;
3850 m_clipLines[y].count = 0;
3857 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3858 Q_CHECK_PTR(m_spans);
3863 m_clipLines[y].spans =
nullptr;
3864 m_clipLines[y].count = 0;
3868 const int len = clipRect.width();
3870 QT_FT_Span *span = m_spans + count;
3874 span->coverage = 255;
3877 m_clipLines[y].spans = span;
3878 m_clipLines[y].count = 1;
3882 while (y < clipSpanHeight) {
3883 m_clipLines[y].spans =
nullptr;
3884 m_clipLines[y].count = 0;
3895 m_clipLines =
nullptr;
3910 ymin = m_spans[0].y;
3911 ymax = m_spans[count-1].y + 1;
3915 const int firstLeft = m_spans[0].x;
3916 const int firstRight = m_spans[0].x + m_spans[0].len;
3919 for (
int i = 0; i <
count; ++i) {
3920 QT_FT_Span_& span = m_spans[i];
3923 if (span.y != y + 1 && y != -1)
3926 m_clipLines[y].spans = &span;
3927 m_clipLines[y]
.count = 1;
3931 const int spanLeft = span.x;
3932 const int spanRight = spanLeft + span.len;
3934 if (spanLeft <
xmin)
3937 if (spanRight >
xmax)
3940 if (spanLeft != firstLeft || spanRight != firstRight)
3946 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3951
3952
3955 if (hasRectClip && rect == clipRect)
3964 xmax = rect.x() + rect.width();
3977
3978
3981 if (region.rectCount() == 1) {
3982 setClipRect(region.boundingRect());
3988 clipRegion = region;
3991 const QRect rect = region.boundingRect();
3993 xmax = rect.x() + rect.width();
3995 ymax = rect.y() + rect.height();
4006
4007
4008
4010 const QT_FT_Span *spans,
const QT_FT_Span *end,
4011 QT_FT_Span **outSpans,
int available)
4015 QT_FT_Span *out = *outSpans;
4017 const QT_FT_Span *clipSpans = clip->m_spans + *currentClip;
4018 const QT_FT_Span *clipEnd = clip->m_spans + clip
->count;
4020 while (available && spans < end ) {
4021 if (clipSpans >= clipEnd) {
4025 if (clipSpans->y > spans->y) {
4029 if (spans->y != clipSpans->y) {
4030 if (spans->y < clip
->count && clip->m_clipLines[spans->y].spans)
4031 clipSpans = clip->m_clipLines[spans->y].spans;
4036 Q_ASSERT(spans->y == clipSpans->y);
4039 int sx2 = sx1 + spans->len;
4040 int cx1 = clipSpans->x;
4041 int cx2 = cx1 + clipSpans->len;
4043 if (cx1 < sx1 && cx2 < sx1) {
4046 }
else if (sx1 < cx1 && sx2 < cx1) {
4050 int x = qMax(sx1, cx1);
4051 int len = qMin(sx2, cx2) - x;
4053 out->x = qMax(sx1, cx1);
4054 out->len = qMin(sx2, cx2) - out->x;
4056 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4068 *currentClip = clipSpans - clip->m_spans;
4075 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4077 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4079 const int NSPANS = 512;
4080 Q_DECL_UNINITIALIZED QT_FT_Span cspans[NSPANS];
4081 int currentClip = 0;
4082 const QT_FT_Span *end = spans + spanCount;
4083 while (spans < end) {
4084 QT_FT_Span *clipped = cspans;
4085 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4089 if (clipped - cspans)
4090 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4095
4096
4097
4098
4102 const int minx = clip.left();
4103 const int miny = clip.top();
4104 const int maxx = clip.right();
4105 const int maxy = clip.bottom();
4107 QT_FT_Span *end = spans + numSpans;
4108 while (spans < end) {
4109 if (spans->y >= miny)
4114 QT_FT_Span *s = spans;
4118 if (s->x > maxx || s->x + s->len <= minx) {
4124 s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
4127 s->len = qMin(s->len, (maxx - s->x + 1));
4139 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4140 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4142 Q_ASSERT(fillData->clip);
4143 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4145 QT_FT_Span *s =
const_cast<QT_FT_Span *>(spans);
4147 count = qt_intersect_spans(s, count,
4148 fillData->clip->clipRect);
4150 fillData->unclipped_blend(count, s, fillData);
4153static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData)
4162 switch (clipData->operation) {
4164 case Qt::IntersectClip:
4169 int currentClip = 0;
4170 const QT_FT_Span *end = spans + count;
4171 while (spans < end) {
4172 QT_FT_Span *newspans = newClip->m_spans + newClip
->count;
4173 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4174 &newspans, newClip->allocated - newClip->count);
4175 newClip
->count = newspans - newClip->m_spans;
4177 newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 *
sizeof(QT_FT_Span)));
4184 case Qt::ReplaceClip:
4185 clipData
->newClip->appendSpans(spans, count);
4197 inline CacheInfo(QGradientStops s,
int op, QGradient::InterpolationMode mode) :
4209 quint64 hash_val = 0;
4211 const QGradientStops stops = gradient.stops();
4212 for (
int i = 0; i < stops.size() && i <= 2; i++)
4213 hash_val += stops[i].second.rgba64();
4215 QMutexLocker lock(&mutex);
4216 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4218 if (it == cache.constEnd())
4219 return addCacheElement(hash_val, gradient, opacity);
4222 const auto &cache_info = it.value();
4223 if (cache_info->stops == stops && cache_info->opacity == opacity && cache_info->interpolationMode == gradient.interpolationMode())
4226 }
while (it != cache.constEnd() && it.key() == hash_val);
4228 return addCacheElement(hash_val, gradient, opacity);
4236 QRgba64 *colorTable,
4237 int size,
int opacity)
const;
4239 if (cache.size() == maxCacheSize()) {
4241 cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize())));
4243 auto cache_entry =
std::make_shared<
CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode());
4244 generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
4245 for (
int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
4246 cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32();
4247 return cache.insert(hash_val, std::move(cache_entry)).value();
4256 const QGradientStops stops = gradient.stops();
4257 int stopCount = stops.size();
4258 Q_ASSERT(stopCount > 0);
4260 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4262 if (stopCount == 2) {
4263 QRgba64 first_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4264 QRgba64 second_color = combineAlpha256(stops[1].second.rgba64(), opacity);
4266 qreal first_stop = stops[0].first;
4267 qreal second_stop = stops[1].first;
4269 if (second_stop < first_stop) {
4270 quint64 tmp = first_color;
4271 first_color = second_color;
4273 qSwap(first_stop, second_stop);
4276 if (colorInterpolation) {
4277 first_color = qPremultiply(first_color);
4278 second_color = qPremultiply(second_color);
4281 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4282 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4284 uint red_first = uint(first_color.red()) << 16;
4285 uint green_first = uint(first_color.green()) << 16;
4286 uint blue_first = uint(first_color.blue()) << 16;
4287 uint alpha_first = uint(first_color.alpha()) << 16;
4289 uint red_second = uint(second_color.red()) << 16;
4290 uint green_second = uint(second_color.green()) << 16;
4291 uint blue_second = uint(second_color.blue()) << 16;
4292 uint alpha_second = uint(second_color.alpha()) << 16;
4295 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4296 if (colorInterpolation)
4297 colorTable[i] = first_color;
4299 colorTable[i] = qPremultiply(first_color);
4302 if (i < second_index) {
4303 qreal reciprocal = qreal(1) / (second_index - first_index);
4305 int red_delta = qRound((qreal(red_second) - red_first) * reciprocal);
4306 int green_delta = qRound((qreal(green_second) - green_first) * reciprocal);
4307 int blue_delta = qRound((qreal(blue_second) - blue_first) * reciprocal);
4308 int alpha_delta = qRound((qreal(alpha_second) - alpha_first) * reciprocal);
4311 red_first += 1 << 15;
4312 green_first += 1 << 15;
4313 blue_first += 1 << 15;
4314 alpha_first += 1 << 15;
4316 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4317 red_first += red_delta;
4318 green_first += green_delta;
4319 blue_first += blue_delta;
4320 alpha_first += alpha_delta;
4322 const QRgba64 color = qRgba64(red_first >> 16, green_first >> 16, blue_first >> 16, alpha_first >> 16);
4324 if (colorInterpolation)
4325 colorTable[i] = color;
4327 colorTable[i] = qPremultiply(color);
4331 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4332 if (colorInterpolation)
4333 colorTable[i] = second_color;
4335 colorTable[i] = qPremultiply(second_color);
4341 QRgba64 current_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4342 if (stopCount == 1) {
4343 current_color = qPremultiply(current_color);
4344 for (
int i = 0; i < size; ++i)
4345 colorTable[i] = current_color;
4350 qreal begin_pos = stops[0].first;
4351 qreal end_pos = stops[stopCount-1].first;
4356 qreal incr = 1 / qreal(size);
4357 qreal dpos = 1.5 * incr;
4360 colorTable[pos++] = qPremultiply(current_color);
4361 while (dpos <= begin_pos) {
4362 colorTable[pos] = colorTable[pos - 1];
4367 int current_stop = 0;
4372 if (dpos < end_pos) {
4374 while (dpos > stops[current_stop+1].first)
4377 if (current_stop != 0)
4378 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4379 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4381 if (colorInterpolation) {
4382 current_color = qPremultiply(current_color);
4383 next_color = qPremultiply(next_color);
4386 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4387 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4388 t = (dpos - stops[current_stop].first) * c;
4392 Q_ASSERT(current_stop < stopCount);
4394 int dist = qRound(t);
4395 int idist = 256 - dist;
4397 if (colorInterpolation)
4398 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
4400 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
4405 if (dpos >= end_pos)
4411 while (dpos > stops[current_stop+skip+1].first)
4415 current_stop += skip;
4417 current_color = next_color;
4419 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4420 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4422 if (colorInterpolation) {
4424 current_color = qPremultiply(current_color);
4425 next_color = qPremultiply(next_color);
4428 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4429 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4430 t = (dpos - stops[current_stop].first) * c;
4437 current_color = qPremultiply(combineAlpha256(stops[stopCount - 1].second.rgba64(), opacity));
4438 while (pos < size - 1) {
4439 colorTable[pos] = current_color;
4444 colorTable[size - 1] = current_color;
4450void QSpanData::init(QRasterBuffer *rb,
const QRasterPaintEngine *pe)
4456 m11 = m22 = m33 = 1.;
4457 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4458 clip = pe ? pe->d_func()->clip() :
nullptr;
4461Q_GUI_EXPORT
extern QImage qt_imageForBrush(
int brushStyle,
bool invert);
4463void QSpanData::setup(
const QBrush &brush,
int alpha, QPainter::CompositionMode compositionMode,
4466 Qt::BrushStyle brushStyle = qbrush_style(brush);
4467 cachedGradient.reset();
4468 switch (brushStyle) {
4469 case Qt::SolidPattern: {
4471 QColor c = qbrush_color(brush);
4472 solidColor = qPremultiplyWithExtraAlpha(c, alpha);
4473 if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
4478 case Qt::LinearGradientPattern:
4480 type = LinearGradient;
4481 const QLinearGradient *g =
static_cast<
const QLinearGradient *>(brush.gradient());
4482 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4484 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4485 gradient.colorTable32 = cacheInfo->buffer32;
4486#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4487 gradient.colorTable64 = cacheInfo->buffer64;
4489 cachedGradient = std::move(cacheInfo);
4491 gradient.spread = g->spread();
4493 QLinearGradientData &linearData = gradient.linear;
4495 linearData.origin.x = g->start().x();
4496 linearData.origin.y = g->start().y();
4497 linearData.end.x = g->finalStop().x();
4498 linearData.end.y = g->finalStop().y();
4502 case Qt::RadialGradientPattern:
4504 type = RadialGradient;
4505 const QRadialGradient *g =
static_cast<
const QRadialGradient *>(brush.gradient());
4506 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4508 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4509 gradient.colorTable32 = cacheInfo->buffer32;
4510#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4511 gradient.colorTable64 = cacheInfo->buffer64;
4513 cachedGradient = std::move(cacheInfo);
4515 gradient.spread = g->spread();
4517 QRadialGradientData &radialData = gradient.radial;
4519 QPointF center = g->center();
4520 radialData.center.x = center.x();
4521 radialData.center.y = center.y();
4522 radialData.center.radius = g->centerRadius();
4523 QPointF focal = g->focalPoint();
4524 radialData.focal.x = focal.x();
4525 radialData.focal.y = focal.y();
4526 radialData.focal.radius = g->focalRadius();
4530 case Qt::ConicalGradientPattern:
4532 type = ConicalGradient;
4533 const QConicalGradient *g =
static_cast<
const QConicalGradient *>(brush.gradient());
4534 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4536 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4537 gradient.colorTable32 = cacheInfo->buffer32;
4538#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4539 gradient.colorTable64 = cacheInfo->buffer64;
4541 cachedGradient = std::move(cacheInfo);
4543 gradient.spread = QGradient::RepeatSpread;
4545 QConicalGradientData &conicalData = gradient.conical;
4547 QPointF center = g->center();
4548 conicalData.center.x = center.x();
4549 conicalData.center.y = center.y();
4550 conicalData.angle = qDegreesToRadians(g->angle());
4554 case Qt::Dense1Pattern:
4555 case Qt::Dense2Pattern:
4556 case Qt::Dense3Pattern:
4557 case Qt::Dense4Pattern:
4558 case Qt::Dense5Pattern:
4559 case Qt::Dense6Pattern:
4560 case Qt::Dense7Pattern:
4561 case Qt::HorPattern:
4562 case Qt::VerPattern:
4563 case Qt::CrossPattern:
4564 case Qt::BDiagPattern:
4565 case Qt::FDiagPattern:
4566 case Qt::DiagCrossPattern:
4569 tempImage =
new QImage();
4570 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle,
true), brush.color());
4571 initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
4573 case Qt::TexturePattern:
4576 tempImage =
new QImage();
4578 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4579 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4581 *tempImage = brush.textureImage();
4582 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4590 adjustSpanMethods();
4593void QSpanData::adjustSpanMethods()
4595 bitmapBlit =
nullptr;
4596 alphamapBlit =
nullptr;
4597 alphaRGBBlit =
nullptr;
4603 unclipped_blend =
nullptr;
4606 const DrawHelper &drawHelper = qDrawHelper[rasterBuffer->format];
4607 unclipped_blend = drawHelper.blendColor;
4608 bitmapBlit = drawHelper.bitmapBlit;
4609 alphamapBlit = drawHelper.alphamapBlit;
4610 alphaRGBBlit = drawHelper.alphaRGBBlit;
4611 fillRect = drawHelper.fillRect;
4614 case LinearGradient:
4615 case RadialGradient:
4616 case ConicalGradient:
4617 unclipped_blend = qBlendGradient;
4620 unclipped_blend = qBlendTexture;
4621 if (!texture.imageData)
4622 unclipped_blend =
nullptr;
4627 if (!unclipped_blend) {
4630 blend = unclipped_blend;
4631 }
else if (clip->hasRectClip) {
4632 blend = clip->clipRect.isEmpty() ?
nullptr : qt_span_fill_clipRect;
4634 blend = qt_span_fill_clipped;
4638void QSpanData::setupMatrix(
const QTransform &matrix,
int bilin)
4642 delta.translate(1.0 / 65536, 1.0 / 65536);
4644 QTransform inv = (delta * matrix).inverted();
4657 const bool affine = inv.isAffine();
4658 const qreal f1 = m11 * m11 + m21 * m21;
4659 const qreal f2 = m12 * m12 + m22 * m22;
4660 fast_matrix = affine
4663 && f1 > (1.0 / 65536)
4664 && f2 > (1.0 / 65536)
4668 adjustSpanMethods();
4671void QSpanData::initTexture(
const QImage *image,
int alpha, QTextureData::Type _type,
const QRect &sourceRect)
4673 const QImageData *d =
const_cast<QImage *>(image)->data_ptr();
4674 if (!d || d->height == 0) {
4675 texture.imageData =
nullptr;
4682 texture.bytesPerLine = 0;
4683 texture.format = QImage::Format_Invalid;
4684 texture.colorTable =
nullptr;
4685 texture.hasAlpha = alpha != 256;
4687 texture.imageData = d->data;
4688 texture.width = d->width;
4689 texture.height = d->height;
4691 if (sourceRect.isNull()) {
4694 texture.x2 = texture.width;
4695 texture.y2 = texture.height;
4697 texture.x1 = sourceRect.x();
4698 texture.y1 = sourceRect.y();
4699 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4700 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4703 texture.bytesPerLine = d->bytes_per_line;
4705 texture.format = d->format;
4706 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable :
nullptr;
4707 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4709 texture.const_alpha = alpha;
4710 texture.type = _type;
4712 adjustSpanMethods();
4716
4717
4718
4722 ProcessSpans pen_func, ProcessSpans brush_func,
4723 QSpanData *pen_data, QSpanData *brush_data)
4728 QT_FT_Span _outline[4];
4729 QT_FT_Span *outline = _outline;
4730 const int midx = rect.x() + (rect.width() + 1) / 2;
4731 const int midy = rect.y() + (rect.height() + 1) / 2;
4737 outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4738 outline[0].len = qMin(length, x - outline[0].x);
4740 outline[0].coverage = 255;
4744 outline[1].len = length;
4746 outline[1].coverage = 255;
4749 outline[2].x = outline[0].x;
4750 outline[2].len = outline[0].len;
4751 outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4752 outline[2].coverage = 255;
4756 outline[3].len = length;
4757 outline[3].y = outline[2].y;
4758 outline[3].coverage = 255;
4760 if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4761 QT_FT_Span _fill[2];
4762 QT_FT_Span *fill = _fill;
4765 fill[0].x = outline[0].x + outline[0].len - 1;
4766 fill[0].len = qMax(0, outline[1].x - fill[0].x);
4767 fill[0].y = outline[1].y;
4768 fill[0].coverage = 255;
4771 fill[1].x = outline[2].x + outline[2].len - 1;
4772 fill[1].len = qMax(0, outline[3].x - fill[1].x);
4773 fill[1].y = outline[3].y;
4774 fill[1].coverage = 255;
4776 int n = (fill[0].y >= fill[1].y ? 1 : 2);
4777 n = qt_intersect_spans(fill, n, clip);
4779 brush_func(n, fill, brush_data);
4782 int n = (outline[1].y >= outline[2].y ? 2 : 4);
4783 n = qt_intersect_spans(outline, n, clip);
4785 pen_func(n, outline, pen_data);
4790
4791
4792
4794 ProcessSpans pen_func, ProcessSpans brush_func,
4795 QSpanData *pen_data, QSpanData *brush_data)
4797 const qreal a = qreal(rect.width()) / 2;
4798 const qreal b = qreal(rect.height()) / 2;
4799 qreal d = b*b - (a*a*b) + 0.25*a*a;
4802 int y = (rect.height() + 1) / 2;
4806 while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4811 d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4812 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4813 pen_func, brush_func, pen_data, brush_data);
4818 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4819 pen_func, brush_func, pen_data, brush_data);
4822 d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4823 const int miny = rect.height() & 0x1;
4826 d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4829 d += a*a*(-2*y + 3);
4832 drawEllipsePoints(x, y, 1, rect, clip,
4833 pen_func, brush_func, pen_data, brush_data);
4838
4839
4840
4841
4845void dumpClip(
int width,
int height,
const QClipData *clip)
4847 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4848 clipImg.fill(0xffff0000);
4855 ((QClipData *) clip)->spans();
4857 for (
int i = 0; i < clip->count; ++i) {
4858 const QT_FT_Span *span = ((QClipData *) clip)->spans() + i;
4859 for (
int j = 0; j < span->len; ++j)
4860 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4861 x0 = qMin(x0,
int(span->x));
4862 x1 = qMax(x1,
int(span->x + span->len - 1));
4864 y0 = qMin(y0,
int(span->y));
4865 y1 = qMax(y1,
int(span->y));
4868 static int counter = 0;
4875 fprintf(stderr,
"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4876 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
Returns true if the rectangle is completely within the current clip state of the paint engine.
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)
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