5#include <QtCore/qglobal.h>
6#include <QtCore/qmutex.h>
8#define QT_FT_BEGIN_HEADER
9#define QT_FT_END_HEADER
11#include <private/qrasterdefs_p.h>
12#include <private/qgrayraster_p.h>
14#include <qpainterpath.h>
22#include <private/qtextengine_p.h>
23#include <private/qfontengine_p.h>
24#include <private/qpixmap_raster_p.h>
26#include <private/qimage_p.h>
27#include <private/qstatictext_p.h>
28#include <private/qcosmeticstroker_p.h>
29#include <private/qdrawhelper_p.h>
30#include <private/qmemrotate_p.h>
31#include <private/qpixellayout_p.h>
32#include <private/qrgba64_p.h>
42# include <qvarlengtharray.h>
43# include <private/qfontengine_p.h>
44# include <qt_windows.h>
54 inline void set(
const QRect &r) {
56 qreal right = r.x() + r.width();
58 qreal bottom = r.y() + r.height();
69 inline void set(
const QRectF &r) {
71 qreal right = r.x() + r.width();
73 qreal bottom = r.y() + r.height();
95#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU_ONLY >= 1600
&& Q_CC_GNU_ONLY < 1700
&& !defined(__OPTIMIZE__)
108#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
109#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
113void dumpClip(
int width,
int height,
const QClipData *clip);
122#define int_dim(pos, dim) (int(pos+dim) - int(pos))
126static inline bool winClearTypeFontsEnabled()
129#if !defined(SPI_GETFONTSMOOTHINGTYPE)
130# define SPI_GETFONTSMOOTHINGTYPE 0x200A
131# define FE_FONTSMOOTHINGCLEARTYPE 0x002
133 SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0);
134 return result == FE_FONTSMOOTHINGCLEARTYPE;
138
139
140bool QRasterPaintEngine::clearTypeFontsEnabled()
142 static const bool result = winClearTypeFontsEnabled();
151
152
155static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData);
171 ProcessSpans pen_func, ProcessSpans brush_func,
172 QSpanData *pen_data, QSpanData *brush_data);
180static const QRectF boundingRect(
const QPointF *points,
int pointCount)
182 const QPointF *e = points;
183 const QPointF *last = points + pointCount;
184 qreal minx, maxx, miny, maxy;
185 minx = maxx = e->x();
186 miny = maxy = e->y();
190 else if (e->x() > maxx)
194 else if (e->y() > maxy)
197 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
203 ((
QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
208 ((
QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
212 qfixed c2x, qfixed c2y,
213 qfixed ex, qfixed ey,
216 ((
QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
217 QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
218 QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
222#if !defined(QT_NO_DEBUG) && 0
223static void qt_debug_path(
const QPainterPath &path)
225 const char *names[] = {
232 fprintf(stderr,
"\nQPainterPath: elementCount=%d\n", path.elementCount());
233 for (
int i=0; i<path.elementCount(); ++i) {
234 const QPainterPath::Element &e = path.elementAt(i);
235 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
236 fprintf(stderr,
" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
242 QPaintEngineExPrivate(),
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
280
281
282
285
286
287
288
289
290
291
292QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
293 : QPaintEngineEx(*(
new QRasterPaintEnginePrivate))
295 d_func()->device = device;
300
301
302QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
305 d_func()->device = device;
309void QRasterPaintEngine::init()
311 Q_D(QRasterPaintEngine);
319 d->grayRaster.reset(
new QT_FT_Raster);
320 Q_CHECK_PTR(d->grayRaster.data());
321 if (QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(d->grayRaster.data()))
322 QT_THROW(std::bad_alloc());
325 d->rasterizer.reset(
new QRasterizer);
326 d->rasterBuffer.reset(
new QRasterBuffer());
327 d->outlineMapper.reset(
new QOutlineMapper);
328 d->outlinemapper_xform_dirty =
true;
330 d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
331 d->basicStroker.setLineToHook(qt_ft_outline_line_to);
332 d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
334 d->baseClip.reset(
new QClipData(d->device->height()));
335 d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
337 d->image_filler.init(d->rasterBuffer.data(),
this);
338 d->image_filler.type = QSpanData::Texture;
340 d->image_filler_xform.init(d->rasterBuffer.data(),
this);
341 d->image_filler_xform.type = QSpanData::Texture;
343 d->solid_color_filler.init(d->rasterBuffer.data(),
this);
344 d->solid_color_filler.type = QSpanData::Solid;
346 d->deviceDepth = d->device->depth();
348 d->mono_surface =
false;
349 gccaps &= ~PorterDuff;
351 QImage::Format format = QImage::Format_Invalid;
353 switch (d->device->devType()) {
354 case QInternal::Pixmap:
355 qWarning(
"QRasterPaintEngine: unsupported for pixmaps...");
357 case QInternal::Image:
358 format = d->rasterBuffer->prepare(
static_cast<QImage *>(d->device));
361 qWarning(
"QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
367 case QImage::Format_MonoLSB:
368 case QImage::Format_Mono:
369 d->mono_surface =
true;
372 if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
373 gccaps |= PorterDuff;
380
381
382QRasterPaintEngine::~QRasterPaintEngine()
384 Q_D(QRasterPaintEngine);
386 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*d->grayRaster.data());
390
391
392bool QRasterPaintEngine::begin(QPaintDevice *device)
394 Q_D(QRasterPaintEngine);
396 if (device->devType() == QInternal::Pixmap) {
397 QPixmap *pixmap =
static_cast<QPixmap *>(device);
398 QPlatformPixmap *pd = pixmap->handle();
399 if (pd->classId() == QPlatformPixmap::RasterClass || pd->classId() == QPlatformPixmap::BlitterClass)
400 d->device = pd->buffer();
408 Q_ASSERT(d->device->devType() == QInternal::Image
409 || d->device->devType() == QInternal::CustomRaster);
411 d->systemStateChanged();
413 QRasterPaintEngineState *s = state();
414 ensureOutlineMapper();
415 d->outlineMapper->setClipRect(d->deviceRect);
416 d->rasterizer->setClipRect(d->deviceRect);
418 s->penData.init(d->rasterBuffer.data(),
this);
419 s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
420 s->stroker = &d->basicStroker;
421 d->basicStroker.setClipRect(d->deviceRect);
423 s->brushData.init(d->rasterBuffer.data(),
this);
424 s->brushData.setup(s->brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
426 d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
428 setDirty(DirtyBrushOrigin);
431 qDebug() <<
"QRasterPaintEngine::begin(" << (
void *) device
432 <<
") devType:" << device->devType()
433 <<
"devRect:" << d->deviceRect;
435 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
440 d->glyphCacheFormat = QFontEngine::Format_Mono;
442 else if (clearTypeFontsEnabled())
447 QImage::Format format =
static_cast<QImage *>(d->device)->format();
448 if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
449 d->glyphCacheFormat = QFontEngine::Format_A32;
451 d->glyphCacheFormat = QFontEngine::Format_A8;
453 d->glyphCacheFormat = QFontEngine::Format_A8;
460
461
462bool QRasterPaintEngine::end()
465 Q_D(QRasterPaintEngine);
466 qDebug() <<
"QRasterPaintEngine::end devRect:" << d->deviceRect;
468 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
476
477
478void QRasterPaintEngine::updateMatrix(
const QTransform &matrix)
480 QRasterPaintEngineState *s = state();
483 s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
485 ensureOutlineMapper();
541 brushData.tempImage =
nullptr;
542 penData.tempImage =
nullptr;
547
548
549QPainterState *QRasterPaintEngine::createState(QPainterState *orig)
const
551 QRasterPaintEngineState *s;
553 s =
new QRasterPaintEngineState();
555 s =
new QRasterPaintEngineState(*
static_cast<QRasterPaintEngineState *>(orig));
561
562
563void QRasterPaintEngine::setState(QPainterState *s)
565 Q_D(QRasterPaintEngine);
566 QPaintEngineEx::setState(s);
567 QRasterPaintEngineState *t = state();
568 if (t->clip && t->clip->enabled != t->clipEnabled) {
570 t->clip->enabled = t->clipEnabled;
572 d->rasterBuffer->compositionMode = s->composition_mode;
576
577
578
581
582
583
586
587
588void QRasterPaintEngine::penChanged()
591 qDebug() <<
"QRasterPaintEngine::penChanged():" << state()->pen;
593 QRasterPaintEngineState *s = state();
595 s->strokeFlags |= DirtyPen;
596 s->dirty |= DirtyPen;
600
601
602void QRasterPaintEngine::updatePen(
const QPen &pen)
604 Q_D(QRasterPaintEngine);
605 QRasterPaintEngineState *s = state();
607 qDebug() <<
"QRasterPaintEngine::updatePen():" << s->pen;
610 Qt::PenStyle pen_style = qpen_style(pen);
615 s->penData.clip = d->clip();
616 s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity,
617 s->composition_mode, s->flags.cosmetic_brush);
619 if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
620 || pen.brush().transform().type() >= QTransform::TxNone) {
621 d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
627 if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
628 pen_style = Qt::SolidLine;
629 s->lastPen.setStyle(Qt::SolidLine);
632 d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
633 d->basicStroker.setCapStyle(qpen_capStyle(pen));
634 d->basicStroker.setMiterLimit(pen.miterLimit());
636 qreal penWidth = qpen_widthf(pen);
638 d->basicStroker.setStrokeWidth(1);
640 d->basicStroker.setStrokeWidth(penWidth);
642 if (pen_style == Qt::SolidLine) {
643 s->stroker = &d->basicStroker;
644 }
else if (pen_style != Qt::NoPen) {
646 d->dashStroker.reset(
new QDashStroker(&d->basicStroker));
647 if (pen.isCosmetic()) {
648 d->dashStroker->setClipRect(d->deviceRect);
651 QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
652 d->dashStroker->setClipRect(clipRect);
654 d->dashStroker->setDashPattern(pen.dashPattern());
655 d->dashStroker->setDashOffset(pen.dashOffset());
656 s->stroker = d->dashStroker.data();
658 s->stroker =
nullptr;
662 bool cosmetic = pen.isCosmetic();
663 s->flags.fast_pen = pen_style > Qt::NoPen
665 && ((cosmetic && penWidth <= 1)
666 || (!cosmetic && (s->flags.tx_noshear || !s->flags.antialiased) && penWidth * s->txscale <= 1));
668 s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
676
677
678void QRasterPaintEngine::brushOriginChanged()
680 QRasterPaintEngineState *s = state();
682 qDebug() <<
"QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
685 s->fillFlags |= DirtyBrushOrigin;
690
691
692void QRasterPaintEngine::brushChanged()
694 QRasterPaintEngineState *s = state();
696 qDebug() <<
"QRasterPaintEngine::brushChanged():" << s->brush;
698 s->fillFlags |= DirtyBrush;
705
706
707void QRasterPaintEngine::updateBrush(
const QBrush &brush)
710 qDebug() <<
"QRasterPaintEngine::updateBrush()" << brush;
712 Q_D(QRasterPaintEngine);
713 QRasterPaintEngineState *s = state();
715 s->brushData.clip = d->clip();
716 s->brushData.setup(brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
717 if (s->fillFlags & DirtyTransform
718 || brush.transform().type() >= QTransform::TxNone)
719 d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
720 s->lastBrush = brush;
724void QRasterPaintEngine::updateOutlineMapper()
726 Q_D(QRasterPaintEngine);
727 d->outlineMapper->setMatrix(state()->matrix);
730void QRasterPaintEngine::updateRasterState()
732 QRasterPaintEngineState *s = state();
734 if (s->dirty & DirtyTransform)
735 updateMatrix(s->matrix);
737 if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
738 const QPainter::CompositionMode mode = s->composition_mode;
739 s->flags.fast_text = (s->penData.type == QSpanData::Solid)
740 && s->intOpacity == 256
741 && (mode == QPainter::CompositionMode_SourceOver
742 || (mode == QPainter::CompositionMode_Source
743 && (s->penData.solidColor.spec() != QColor::ExtendedRgb &&
744 s->penData.solidColor.alphaF() >= 1.0f)));
752
753
754void QRasterPaintEngine::opacityChanged()
756 QRasterPaintEngineState *s = state();
759 qDebug() <<
"QRasterPaintEngine::opacityChanged()" << s->opacity;
762 s->fillFlags |= DirtyOpacity;
763 s->strokeFlags |= DirtyOpacity;
764 s->pixmapFlags |= DirtyOpacity;
765 s->dirty |= DirtyOpacity;
766 s->intOpacity = (
int) (s->opacity * 256);
770
771
772void QRasterPaintEngine::compositionModeChanged()
774 Q_D(QRasterPaintEngine);
775 QRasterPaintEngineState *s = state();
778 qDebug() <<
"QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
781 s->fillFlags |= DirtyCompositionMode;
782 s->dirty |= DirtyCompositionMode;
784 s->strokeFlags |= DirtyCompositionMode;
785 d->rasterBuffer->compositionMode = s->composition_mode;
787 d->recalculateFastImages();
791
792
793void QRasterPaintEngine::renderHintsChanged()
795 QRasterPaintEngineState *s = state();
798 qDebug() <<
"QRasterPaintEngine::renderHintsChanged()" << Qt::hex << s->renderHints;
801 bool was_aa = s->flags.antialiased;
802 bool was_bilinear = s->flags.bilinear;
803 bool was_cosmetic_brush = s->flags.cosmetic_brush;
805 s->flags.antialiased =
bool(s->renderHints & QPainter::Antialiasing);
806 s->flags.bilinear =
bool(s->renderHints & QPainter::SmoothPixmapTransform);
807 s->flags.cosmetic_brush = !
bool(s->renderHints & QPainter::NonCosmeticBrushPatterns);
809 if (was_aa != s->flags.antialiased)
810 s->strokeFlags |= DirtyHints;
812 if (was_bilinear != s->flags.bilinear || was_cosmetic_brush != s->flags.cosmetic_brush) {
813 s->strokeFlags |= DirtyPen;
814 s->fillFlags |= DirtyBrush;
817 Q_D(QRasterPaintEngine);
818 d->recalculateFastImages();
820 if (was_aa != s->flags.antialiased)
825
826
827void QRasterPaintEngine::transformChanged()
829 QRasterPaintEngineState *s = state();
832 qDebug() <<
"QRasterPaintEngine::transformChanged()" << s->matrix;
835 s->fillFlags |= DirtyTransform;
836 s->strokeFlags |= DirtyTransform;
838 s->dirty |= DirtyTransform;
840 Q_D(QRasterPaintEngine);
841 d->recalculateFastImages();
845
846
847void QRasterPaintEngine::clipEnabledChanged()
849 QRasterPaintEngineState *s = state();
852 qDebug() <<
"QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
856 s->clip->enabled = s->clipEnabled;
857 s->fillFlags |= DirtyClipEnabled;
858 s->strokeFlags |= DirtyClipEnabled;
859 s->pixmapFlags |= DirtyClipEnabled;
865 SrcOverBlendFunc func,
870 if (alpha == 0 || !clip.isValid())
872 if (pt.x() > qreal(clip.right()) || pt.y() > qreal(clip.bottom()))
874 if ((pt.x() + img.width()) < qreal(clip.left()) || (pt.y() + img.height()) < qreal(clip.top()))
877 Q_ASSERT(img.depth() >= 8);
879 qsizetype srcBPL = img.bytesPerLine();
880 const uchar *srcBits = img.bits();
881 int srcSize = img.depth() >> 3;
882 int iw = img.width();
883 int ih = img.height();
889 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
893 int x = qRound(pt.x());
895 int cx2 = clip.x() + clip.width();
898 srcBits += srcSize * d;
903 int d = x + iw - cx2;
911 int cy2 = clip.y() + clip.height();
912 int y = qRound(pt.y());
915 srcBits += srcBPL * d;
920 int d = y + ih - cy2;
927 int dstSize = rasterBuffer->bytesPerPixel();
928 qsizetype dstBPL = rasterBuffer->bytesPerLine();
929 func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
942 if (pt.x() > qreal(clip.right()) || pt.y() > qreal(clip.bottom()))
944 if ((pt.x() + img.width()) < qreal(clip.left()) || (pt.y() + img.height()) < qreal(clip.top()))
947 Q_ASSERT(img.depth() >= 8);
949 qsizetype srcBPL = img.bytesPerLine();
950 const uchar *srcBits = img.bits();
951 int srcSize = img.depth() >> 3;
952 int iw = img.width();
953 int ih = img.height();
959 srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
963 int x = qRound(pt.x());
965 int cx2 = clip.x() + clip.width();
968 srcBits += srcSize * d;
973 int d = x + iw - cx2;
981 int cy2 = clip.y() + clip.height();
982 int y = qRound(pt.y());
985 srcBits += srcBPL * d;
990 int d = y + ih - cy2;
997 int dstSize = rasterBuffer->bytesPerPixel();
998 qsizetype dstBPL = rasterBuffer->bytesPerLine();
999 const uint *src = (
const uint *) srcBits;
1000 uint *dst =
reinterpret_cast<uint *>(rasterBuffer->buffer() + x * dstSize + y * dstBPL);
1002 const int len = iw * (qt_depthForFormat(rasterBuffer->format) >> 3);
1003 for (
int y = 0; y < ih; ++y) {
1004 memcpy(dst, src, len);
1005 dst = (quint32 *)(((uchar *) dst) + dstBPL);
1006 src = (
const quint32 *)(((
const uchar *) src) + srcBPL);
1013 deviceRectUnclipped = QRect(0, 0,
1014 qMin(QT_RASTER_COORD_LIMIT, device->width()),
1015 qMin(QT_RASTER_COORD_LIMIT, device->height()));
1017 if (!systemClip.isEmpty()) {
1018 QRegion clippedDeviceRgn = systemClip & deviceRectUnclipped;
1019 deviceRect = clippedDeviceRgn.boundingRect();
1020 baseClip->setClipRegion(clippedDeviceRgn);
1022 deviceRect = deviceRectUnclipped;
1023 baseClip->setClipRect(deviceRect);
1026 qDebug() <<
"systemStateChanged" <<
this <<
"deviceRect" << deviceRect << deviceRectUnclipped << systemClip;
1029 exDeviceRect = deviceRect;
1031 Q_Q(QRasterPaintEngine);
1033 q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1034 q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1035 q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1041 if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1044 Q_Q(QRasterPaintEngine);
1045 bool bilinear = q->state()->flags.bilinear;
1047 if (b.d->transform.type() > QTransform::TxNone) {
1048 spanData->setupMatrix(b.transform() * m, bilinear);
1050 if (m.type() <= QTransform::TxTranslate) {
1060 spanData->dx = -m.dx();
1061 spanData->dy = -m.dy();
1062 spanData->txop = m.type();
1063 spanData->bilinear = bilinear;
1064 spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1065 spanData->adjustSpanMethods();
1067 spanData->setupMatrix(m, bilinear);
1074#ifdef QT_CLIPPING_RATIOS
1079static void checkClipRatios(QRasterPaintEnginePrivate *d)
1081 if (d->clip()->hasRectClip)
1083 if (d->clip()->hasRegionClip)
1087 if ((totalClips % 5000) == 0) {
1088 printf(
"Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1089 rectClips * 100.0 / (qreal) totalClips,
1090 regionClips * 100.0 / (qreal) totalClips,
1091 (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1110 s->fillFlags |= QPaintEngine::DirtyClipPath;
1111 s->strokeFlags |= QPaintEngine::DirtyClipPath;
1112 s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1114 d->solid_color_filler.clip = d
->clip();
1115 d->solid_color_filler.adjustSpanMethods();
1118 dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1125
1126
1127void QRasterPaintEngine::clip(
const QVectorPath &path, Qt::ClipOperation op)
1130 qDebug() <<
"QRasterPaintEngine::clip(): " << path << op;
1132 if (path.elements()) {
1133 for (
int i=0; i<path.elementCount(); ++i) {
1134 qDebug() <<
" - " << path.elements()[i]
1135 <<
'(' << path.points()[i*2] <<
", " << path.points()[i*2+1] <<
')';
1138 for (
int i=0; i<path.elementCount(); ++i) {
1139 qDebug() <<
" ---- "
1140 <<
'(' << path.points()[i*2] <<
", " << path.points()[i*2+1] <<
')';
1145 Q_D(QRasterPaintEngine);
1146 QRasterPaintEngineState *s = state();
1149 if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
1150 if (s->matrix.type() <= QTransform::TxScale
1153 qDebug(
" --- optimizing vector clip to rect clip...");
1155 const qreal *points = path.points();
1156 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1157 if (setClipRectInDeviceCoords(qt_mapFillRect(r, s->matrix), op))
1162 if (op == Qt::NoClip) {
1163 qrasterpaintengine_state_setNoClip(s);
1166 QClipData *base = d->baseClip.data();
1169 if (op == Qt::IntersectClip && s->clip)
1175 Qt::ClipOperation isectOp = Qt::IntersectClip;
1176 if (base ==
nullptr)
1177 isectOp = Qt::ReplaceClip;
1179 QClipData *newClip =
new QClipData(d->rasterBuffer->height());
1180 newClip->initialize();
1181 ClipData clipData = { base, newClip, isectOp };
1182 ensureOutlineMapper();
1183 d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData,
nullptr);
1187 if (s->flags.has_clip_ownership)
1191 s->flags.has_clip_ownership =
true;
1193 qrasterpaintengine_dirty_clip(d, s);
1199
1200
1201void QRasterPaintEngine::clip(
const QRect &rect, Qt::ClipOperation op)
1204 qDebug() <<
"QRasterPaintEngine::clip(): " << rect << op;
1207 QRasterPaintEngineState *s = state();
1209 if (op == Qt::NoClip) {
1210 qrasterpaintengine_state_setNoClip(s);
1212 }
else if (s->matrix.type() > QTransform::TxScale) {
1213 QPaintEngineEx::clip(rect, op);
1216 }
else if (!setClipRectInDeviceCoords(qt_mapFillRect(rect, s->matrix), op)) {
1217 QPaintEngineEx::clip(rect, op);
1223bool QRasterPaintEngine::setClipRectInDeviceCoords(
const QRect &r, Qt::ClipOperation op)
1225 Q_D(QRasterPaintEngine);
1226 QRect clipRect = r & d->deviceRect;
1227 QRasterPaintEngineState *s = state();
1229 if (op == Qt::ReplaceClip || s->clip ==
nullptr) {
1233 QRegion clipRegion = systemClip();
1234 QClipData *clip =
new QClipData(d->rasterBuffer->height());
1236 if (clipRegion.isEmpty())
1237 clip->setClipRect(clipRect);
1239 clip->setClipRegion(clipRegion & clipRect);
1241 if (s->flags.has_clip_ownership)
1245 s->clip->enabled =
true;
1246 s->flags.has_clip_ownership =
true;
1248 }
else if (op == Qt::IntersectClip){
1249 QClipData *base = s->clip;
1252 if (base->hasRectClip || base->hasRegionClip) {
1253 if (!s->flags.has_clip_ownership) {
1254 s->clip =
new QClipData(d->rasterBuffer->height());
1255 s->flags.has_clip_ownership =
true;
1257 if (base->hasRectClip)
1258 s->clip->setClipRect(base->clipRect & clipRect);
1260 s->clip->setClipRegion(base->clipRegion & clipRect);
1261 s->clip->enabled =
true;
1269 qrasterpaintengine_dirty_clip(d, s);
1275
1276
1277void QRasterPaintEngine::clip(
const QRegion ®ion, Qt::ClipOperation op)
1280 qDebug() <<
"QRasterPaintEngine::clip(): " << region << op;
1283 Q_D(QRasterPaintEngine);
1285 if (region.rectCount() == 1) {
1286 clip(region.boundingRect(), op);
1290 QRasterPaintEngineState *s = state();
1291 const QClipData *clip = d->clip();
1292 const QClipData *baseClip = d->baseClip.data();
1294 if (op == Qt::NoClip) {
1295 qrasterpaintengine_state_setNoClip(s);
1296 }
else if (s->matrix.type() > QTransform::TxScale
1297 || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1298 || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1299 QPaintEngineEx::clip(region, op);
1301 const QClipData *curClip;
1304 if (op == Qt::IntersectClip)
1309 if (s->flags.has_clip_ownership) {
1313 newClip =
new QClipData(d->rasterBuffer->height());
1315 s->flags.has_clip_ownership =
true;
1318 QRegion r = s->matrix.map(region);
1319 if (curClip->hasRectClip)
1320 newClip->setClipRegion(r & curClip->clipRect);
1321 else if (curClip->hasRegionClip)
1322 newClip->setClipRegion(r & curClip->clipRegion);
1324 qrasterpaintengine_dirty_clip(d, s);
1329
1330
1331
1332
1336
1337
1338void QRasterPaintEngine::fillPath(
const QPainterPath &path, QSpanData *fillData)
1341 qDebug() <<
" --- fillPath, bounds=" << path.boundingRect();
1344 if (!fillData->blend)
1347 Q_D(QRasterPaintEngine);
1349 const QRectF controlPointRect = path.controlPointRect();
1351 QRasterPaintEngineState *s = state();
1352 const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1353 ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1354 const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1355 || deviceRect.right() > QT_RASTER_COORD_LIMIT
1356 || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1357 || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1359 if (!s->flags.antialiased && !do_clip) {
1360 d->initializeRasterizer(fillData);
1361 d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1365 ensureOutlineMapper();
1366 d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1374 bool rectClipped =
true;
1377 x1 = qMax(r.x(), data->clip->xmin);
1378 x2 = qMin(r.x() + r.width(), data->clip->xmax);
1379 y1 = qMax(r.y(), data->clip->ymin);
1380 y2 = qMin(r.y() + r.height(), data->clip->ymax);
1381 rectClipped = data->clip->hasRectClip;
1384 x1 = qMax(r.x(), pe->deviceRect.x());
1385 x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1386 y1 = qMax(r.y(), pe->deviceRect.y());
1387 y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1389 x1 = qMax(r.x(), 0);
1390 x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1391 y1 = qMax(r.y(), 0);
1392 y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1395 if (x2 <= x1 || y2 <= y1)
1398 const int width = x2 - x1;
1399 const int height = y2 - y1;
1401 bool isUnclipped = rectClipped
1402 || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1404 if (pe && isUnclipped) {
1405 const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1407 if (data->fillRect && (mode == QPainter::CompositionMode_Source
1408 || (mode == QPainter::CompositionMode_SourceOver
1409 && (data->solidColor.spec() != QColor::ExtendedRgb &&
1410 data->solidColor.alphaF() >= 1.0f))))
1412 data->fillRect(data->rasterBuffer, x1, y1, width, height, data->solidColor.rgba64());
1417 ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1419 const int nspans = 512;
1420 Q_DECL_UNINITIALIZED QT_FT_Span spans[nspans];
1422 Q_ASSERT(data->blend);
1425 int n = qMin(nspans, y2 - y);
1429 spans[i].len = width;
1431 spans[i].coverage = 255;
1435 blend(n, spans, data);
1441
1442
1443void QRasterPaintEngine::drawRects(
const QRect *rects,
int rectCount)
1446 qDebug(
" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1448 Q_D(QRasterPaintEngine);
1449 ensureRasterState();
1450 QRasterPaintEngineState *s = state();
1454 if (s->brushData.blend) {
1455 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1456 const QRect *r = rects;
1457 const QRect *lastRect = rects + rectCount;
1459 int offset_x =
int(s->matrix.dx());
1460 int offset_y =
int(s->matrix.dy());
1461 while (r < lastRect) {
1462 QRect rect = r->normalized();
1463 QRect rr = rect.translated(offset_x, offset_y);
1464 fillRect_normalized(rr, &s->brushData, d);
1468 QRectVectorPath path;
1469 for (
int i=0; i<rectCount; ++i) {
1471 fill(path, s->brush);
1477 if (s->penData.blend) {
1478 QRectVectorPath path;
1479 if (s->flags.fast_pen) {
1480 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1481 for (
int i = 0; i < rectCount; ++i) {
1483 stroker.drawPath(path);
1486 for (
int i = 0; i < rectCount; ++i) {
1488 stroke(path, s->pen);
1495
1496
1497void QRasterPaintEngine::drawRects(
const QRectF *rects,
int rectCount)
1500 qDebug(
" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1503 Q_D(QRasterPaintEngine);
1504 ensureRasterState();
1505 QRasterPaintEngineState *s = state();
1508 if (s->flags.tx_noshear) {
1510 if (s->brushData.blend) {
1511 d->initializeRasterizer(&s->brushData);
1512 for (
int i = 0; i < rectCount; ++i) {
1513 const QRectF &rect = rects[i].normalized();
1516 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1517 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1518 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1523 if (s->penData.blend) {
1524 QRectVectorPath path;
1525 if (s->flags.fast_pen) {
1526 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1527 for (
int i = 0; i < rectCount; ++i) {
1529 stroker.drawPath(path);
1532 for (
int i = 0; i < rectCount; ++i) {
1534 QPaintEngineEx::stroke(path, s->lastPen);
1542 QPaintEngineEx::drawRects(rects, rectCount);
1547
1548
1549void QRasterPaintEngine::stroke(
const QVectorPath &path,
const QPen &pen)
1551 Q_D(QRasterPaintEngine);
1552 QRasterPaintEngineState *s = state();
1555 if (!s->penData.blend)
1558 if (s->flags.fast_pen) {
1559 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1560 stroker.drawPath(path);
1561 }
else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1562 qreal width = s->lastPen.isCosmetic()
1563 ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1564 : qpen_widthf(s->lastPen) * s->txscale;
1566 qreal dashOffset = s->lastPen.dashOffset();
1568 qreal patternLength = 0;
1569 const QList<qreal> pattern = s->lastPen.dashPattern();
1570 for (
int i = 0; i < pattern.size(); ++i)
1571 patternLength += pattern.at(i);
1573 if (patternLength > 0) {
1574 dashOffset = std::fmod(dashOffset, patternLength);
1576 dashOffset += patternLength;
1577 while (dashOffset >= pattern.at(dashIndex)) {
1578 dashOffset -= pattern.at(dashIndex);
1579 if (++dashIndex >= pattern.size())
1585 Q_D(QRasterPaintEngine);
1586 d->initializeRasterizer(&s->penData);
1587 int lineCount = path.elementCount() / 2;
1588 const QLineF *lines =
reinterpret_cast<
const QLineF *>(path.points());
1590 for (
int i = 0; i < lineCount; ++i) {
1591 const QLineF line = s->matrix.map(lines[i]);
1592 if (line.p1() == line.p2()) {
1593 if (s->lastPen.capStyle() != Qt::FlatCap) {
1594 const QPointF delta(width / 2, 0);
1595 d->rasterizer->rasterizeLine(line.p1() - delta, line.p1() + delta, 1);
1600 if (qpen_style(s->lastPen) == Qt::SolidLine) {
1601 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1602 width / line.length(),
1603 s->lastPen.capStyle() == Qt::SquareCap);
1606 int dIndex = dashIndex;
1607 qreal dOffset = dashOffset;
1609 d->rasterizeLine_dashed(line, width, &dIndex, &dOffset, &inD);
1614 QPaintEngineEx::stroke(path, pen);
1617QRect QRasterPaintEngine::toNormalizedFillRect(
const QRectF &rect)
1619 int x1 = qRound(rect.x());
1620 int y1 = qRound(rect.y());
1621 int x2 = qRound(rect.right());
1622 int y2 = qRound(rect.bottom());
1629 return QRect(x1, y1, x2 - x1, y2 - y1);
1633
1634
1635void QRasterPaintEngine::fill(
const QVectorPath &path,
const QBrush &brush)
1640 QRectF rf = path.controlPointRect();
1641 qDebug() <<
"QRasterPaintEngine::fill(): "
1642 <<
"size=" << path.elementCount()
1643 <<
", hints=" << Qt::hex << path.hints()
1647 Q_D(QRasterPaintEngine);
1648 QRasterPaintEngineState *s = state();
1651 if (!s->brushData.blend)
1654 if (path.shape() == QVectorPath::RectangleHint) {
1655 if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1656 const qreal *p = path.points();
1657 QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1658 QPointF br = QPointF(p[4], p[5]) * s->matrix;
1659 fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1662 ensureRasterState();
1663 if (s->flags.tx_noshear) {
1664 d->initializeRasterizer(&s->brushData);
1666 const qreal *p = path.points();
1667 QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1669 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1670 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1671 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1678 QRectF cpRect = path.controlPointRect();
1679 const QRectF pathDeviceRect = s->matrix.mapRect(cpRect);
1681 if (!pathDeviceRect.intersects(QRectF(d->deviceRect)) || !pathDeviceRect.isValid())
1684 ProcessSpans blend = d->getBrushFunc(pathDeviceRect, &s->brushData);
1699 ensureOutlineMapper();
1700 d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1703void QRasterPaintEngine::fillRect(
const QRectF &r, QSpanData *data)
1705 Q_D(QRasterPaintEngine);
1706 QRasterPaintEngineState *s = state();
1708 if (!s->flags.antialiased) {
1709 uint txop = s->matrix.type();
1710 if (txop == QTransform::TxNone) {
1711 fillRect_normalized(toNormalizedFillRect(r), data, d);
1713 }
else if (txop == QTransform::TxTranslate) {
1714 const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1715 fillRect_normalized(rr, data, d);
1717 }
else if (txop == QTransform::TxScale) {
1718 const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1719 fillRect_normalized(rr, data, d);
1723 ensureRasterState();
1724 if (s->flags.tx_noshear) {
1725 d->initializeRasterizer(data);
1726 QRectF nr = r.normalized();
1727 if (!nr.isEmpty()) {
1728 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1729 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1730 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1737 ensureOutlineMapper();
1738 fillPath(path, data);
1742
1743
1744void QRasterPaintEngine::fillRect(
const QRectF &r,
const QBrush &brush)
1747 qDebug() <<
"QRasterPaintEngine::fillRecct(): " << r << brush;
1749 QRasterPaintEngineState *s = state();
1752 if (!s->brushData.blend)
1755 fillRect(r, &s->brushData);
1761 return Qt::transparent;
1762 if (c.spec() == QColor::ExtendedRgb) {
1764 c.getRgbF(&r, &g, &b, &a);
1765 a = a * alpha * (1.f / 256.f);
1766 return QColor::fromRgbF(r * a, g * a, b * a, a);
1768 return qPremultiply(combineAlpha256(c.rgba64(), alpha));
1772
1773
1774void QRasterPaintEngine::fillRect(
const QRectF &r,
const QColor &color)
1777 qDebug() <<
"QRasterPaintEngine::fillRect(): " << r << color;
1779 Q_D(QRasterPaintEngine);
1780 QRasterPaintEngineState *s = state();
1782 d->solid_color_filler.solidColor = qPremultiplyWithExtraAlpha(color, s->intOpacity);
1784 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f
1785 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1788 d->solid_color_filler.clip = d->clip();
1789 d->solid_color_filler.adjustSpanMethods();
1790 fillRect(r, &d->solid_color_filler);
1793static inline bool isAbove(
const QPointF *a,
const QPointF *b)
1795 return a->y() < b->y();
1798static bool splitPolygon(
const QPointF *points,
int pointCount, QList<QPointF> *upper, QList<QPointF> *lower)
1803 Q_ASSERT(pointCount >= 2);
1805 QList<
const QPointF *> sorted;
1806 sorted.reserve(pointCount);
1808 upper->reserve(pointCount * 3 / 4);
1809 lower->reserve(pointCount * 3 / 4);
1811 for (
int i = 0; i < pointCount; ++i)
1812 sorted << points + i;
1814 std::sort(sorted.begin(), sorted.end(), isAbove);
1816 qreal splitY = sorted.at(sorted.size() / 2)->y();
1818 const QPointF *end = points + pointCount;
1819 const QPointF *last = end - 1;
1821 QList<QPointF> *bin[2] = { upper, lower };
1823 for (
const QPointF *p = points; p < end; ++p) {
1824 int side = p->y() < splitY;
1825 int lastSide = last->y() < splitY;
1827 if (side != lastSide) {
1828 if (qFuzzyCompare(p->y(), splitY)) {
1829 bin[!side]->append(*p);
1830 }
else if (qFuzzyCompare(last->y(), splitY)) {
1831 bin[side]->append(*last);
1833 QPointF delta = *p - *last;
1834 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1836 bin[0]->append(intersection);
1837 bin[1]->append(intersection);
1841 bin[side]->append(*p);
1847 return upper->size() < pointCount && lower->size() < pointCount;
1851
1852
1853void QRasterPaintEngine::fillPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1855 Q_D(QRasterPaintEngine);
1856 QRasterPaintEngineState *s = state();
1858 const int maxPoints = 0xffff;
1861 if (pointCount > maxPoints) {
1862 QList<QPointF> upper, lower;
1864 if (splitPolygon(points, pointCount, &upper, &lower)) {
1865 fillPolygon(upper.constData(), upper.size(), mode);
1866 fillPolygon(lower.constData(), lower.size(), mode);
1868 qWarning(
"Polygon too complex for filling.");
1874 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1875 ensureOutlineMapper();
1876 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1879 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1881 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1885
1886
1887void QRasterPaintEngine::drawPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1889 Q_D(QRasterPaintEngine);
1890 QRasterPaintEngineState *s = state();
1893 qDebug(
" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1894 for (
int i=0; i<pointCount; ++i)
1895 qDebug() <<
" - " << points[i];
1897 Q_ASSERT(pointCount >= 2);
1899 if (mode != PolylineMode && QVectorPath::isRect((
const qreal *) points, pointCount)) {
1900 QRectF r(points[0], points[2]);
1906 if (mode != PolylineMode) {
1909 if (s->brushData.blend)
1910 fillPolygon(points, pointCount, mode);
1914 if (s->penData.blend) {
1915 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1916 if (s->flags.fast_pen) {
1917 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1918 stroker.drawPath(vp);
1920 QPaintEngineEx::stroke(vp, s->lastPen);
1926
1927
1928void QRasterPaintEngine::drawPolygon(
const QPoint *points,
int pointCount, PolygonDrawMode mode)
1930 Q_D(QRasterPaintEngine);
1931 QRasterPaintEngineState *s = state();
1934 qDebug(
" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1935 for (
int i=0; i<pointCount; ++i)
1936 qDebug() <<
" - " << points[i];
1938 Q_ASSERT(pointCount >= 2);
1939 if (mode != PolylineMode && QVectorPath::isRect((
const int *) points, pointCount)) {
1940 QRect r(points[0].x(),
1942 points[2].x() - points[0].x(),
1943 points[2].y() - points[0].y());
1951 if (mode != PolylineMode) {
1953 if (s->brushData.blend) {
1955 ensureOutlineMapper();
1956 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1957 d->outlineMapper->moveTo(*points);
1958 const QPoint *p = points;
1959 const QPoint *ep = points + pointCount - 1;
1961 d->outlineMapper->lineTo(*(++p));
1963 d->outlineMapper->endOutline();
1966 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1968 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
1973 if (s->penData.blend) {
1974 int count = pointCount * 2;
1975 QVarLengthArray<qreal> fpoints(count);
1976 for (
int i=0; i<count; ++i)
1977 fpoints[i] = ((
const int *) points)[i];
1978 QVectorPath vp((qreal *) fpoints.data(), pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1980 if (s->flags.fast_pen) {
1981 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1982 stroker.drawPath(vp);
1984 QPaintEngineEx::stroke(vp, s->lastPen);
1990
1991
1992void QRasterPaintEngine::drawPixmap(
const QPointF &pos,
const QPixmap &pixmap)
1995 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), pos=" << pos <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
1998 QPlatformPixmap *pd = pixmap.handle();
1999 if (pd->classId() == QPlatformPixmap::RasterClass) {
2000 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2001 if (image.depth() == 1) {
2002 Q_D(QRasterPaintEngine);
2003 QRasterPaintEngineState *s = state();
2004 if (s->matrix.type() <= QTransform::TxTranslate) {
2006 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2008 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2011 QRasterPaintEngine::drawImage(pos, image);
2014 const QImage image = pixmap.toImage();
2015 if (pixmap.depth() == 1) {
2016 Q_D(QRasterPaintEngine);
2017 QRasterPaintEngineState *s = state();
2018 if (s->matrix.type() <= QTransform::TxTranslate) {
2020 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2022 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2025 QRasterPaintEngine::drawImage(pos, image);
2031
2032
2033void QRasterPaintEngine::drawPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QRectF &sr)
2036 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), r=" << r <<
" sr=" << sr <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
2039 QPlatformPixmap* pd = pixmap.handle();
2040 if (pd->classId() == QPlatformPixmap::RasterClass) {
2041 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2042 if (image.depth() == 1) {
2043 Q_D(QRasterPaintEngine);
2044 QRasterPaintEngineState *s = state();
2045 if (s->matrix.type() <= QTransform::TxTranslate
2046 && r.size() == sr.size()
2047 && r.size() == pixmap.size()) {
2049 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2052 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2055 drawImage(r, image, sr);
2058 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2059 const QImage image = pd->toImage(clippedSource);
2060 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2061 if (image.depth() == 1) {
2062 Q_D(QRasterPaintEngine);
2063 QRasterPaintEngineState *s = state();
2064 if (s->matrix.type() <= QTransform::TxTranslate
2065 && r.size() == sr.size()
2066 && r.size() == pixmap.size()) {
2068 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2071 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2074 drawImage(r, image, translatedSource);
2081 const int iv =
int(v);
2090 const int xmin =
int(rect.x());
2091 const int xmax =
int(fast_ceil_positive(rect.right()));
2092 const int ymin =
int(rect.y());
2093 const int ymax =
int(fast_ceil_positive(rect.bottom()));
2094 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2098
2099
2100void QRasterPaintEngine::drawImage(
const QPointF &p,
const QImage &img)
2103 qDebug() <<
" - QRasterPaintEngine::drawImage(), p=" << p <<
" image=" << img.size() <<
"depth=" << img.depth();
2106 Q_D(QRasterPaintEngine);
2107 QRasterPaintEngineState *s = state();
2108 qreal scale = img.devicePixelRatio();
2110 if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) {
2111 drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
2113 QRectF(0, 0, img.width(), img.height()));
2116 const QClipData *clip = d->clip();
2117 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2119 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, img.rect())) {
2121 d->blitImage(pt, img, d->deviceRect);
2123 }
else if (clip->hasRectClip) {
2124 d->blitImage(pt, img, clip->clipRect);
2127 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2128 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2131 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2133 }
else if (clip->hasRectClip) {
2134 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2142 d->image_filler.clip = clip;
2143 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2144 if (!d->image_filler.blend)
2146 d->image_filler.dx = -pt.x();
2147 d->image_filler.dy = -pt.y();
2148 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2150 fillRect_normalized(rr, &d->image_filler, d);
2157 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2168 inline RotationType qRotationType(
const QTransform &transform)
2170 QTransform::TransformationType type = transform.type();
2172 if (type > QTransform::TxRotate)
2175 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2176 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2179 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2180 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2183 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2184 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2190 inline bool isPixelAligned(
const QPointF &pt)
2192 return QPointF(pt.toPoint()) == pt;
2194 inline bool isPixelAligned(
const QRectF &rect)
2196 return QRectF(rect.toRect()) == rect;
2201
2202
2203void QRasterPaintEngine::drawImage(
const QRectF &r,
const QImage &img,
const QRectF &sr,
2204 Qt::ImageConversionFlags)
2207 qDebug() <<
" - QRasterPaintEngine::drawImage(), r=" << r <<
" sr=" << sr <<
" image=" << img.size() <<
"depth=" << img.depth();
2213 Q_D(QRasterPaintEngine);
2214 QRasterPaintEngineState *s = state();
2216 int sr_l = qFloor(sr.left());
2217 int sr_r = qCeil(sr.right()) - 1;
2218 int sr_t = qFloor(sr.top());
2219 int sr_b = qCeil(sr.bottom()) - 1;
2221 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2224 QTransform old = s->matrix;
2227 QRgb color = img.pixel(sr_l, sr_t);
2228 if (img.pixelFormat().premultiplied() == QPixelFormat::Premultiplied) {
2230 d->solid_color_filler.solidColor = multiplyAlpha256(QRgba64::fromArgb32(color), s->intOpacity);
2232 d->solid_color_filler.solidColor = qPremultiply(combineAlpha256(QRgba64::fromArgb32(color), s->intOpacity));
2235 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f && s->composition_mode == QPainter::CompositionMode_SourceOver)
2238 d->solid_color_filler.clip = d->clip();
2239 d->solid_color_filler.adjustSpanMethods();
2240 fillRect(r, &d->solid_color_filler);
2246 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2248 const QClipData *clip = d->clip();
2250 if (s->matrix.type() == QTransform::TxRotate
2252 && (!clip || clip->hasRectClip)
2253 && s->intOpacity == 256
2254 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2255 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
2257 RotationType rotationType = qRotationType(s->matrix);
2258 Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats);
2259 const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
2261 if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2262 QRectF transformedTargetRect = s->matrix.mapRect(r);
2264 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, transformedTargetRect.topRight(), sr)) {
2265 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2266 if (clippedTransformedTargetRect.isNull())
2269 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2271 QRect clippedSourceRect
2272 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2273 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2275 clippedSourceRect = clippedSourceRect.intersected(img.rect());
2277 const qsizetype dbpl = d->rasterBuffer->bytesPerLine();
2278 const qsizetype sbpl = img.bytesPerLine();
2280 uchar *dst = d->rasterBuffer->buffer();
2281 uint bpp = img.depth() >> 3;
2283 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2284 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2286 uint cw = clippedSourceRect.width();
2287 uint ch = clippedSourceRect.height();
2289 qMemRotateFunctions[plBpp][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2296 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2298 QRectF targetBounds = s->matrix.mapRect(r);
2299 bool exceedsPrecision = r.width() > 0x7fff
2300 || r.height() > 0x7fff
2301 || targetBounds.left() < -0x7fff
2302 || targetBounds.top() < -0x7fff
2303 || targetBounds.right() > 0x7fff
2304 || targetBounds.bottom() > 0x7fff
2305 || targetBounds.width() > 0x7fff
2306 || targetBounds.height() > 0x7fff
2307 || s->matrix.m11() >= 512
2308 || s->matrix.m22() >= 512;
2309 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2310 if (s->matrix.type() > QTransform::TxScale) {
2311 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2314 if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) {
2315 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2316 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2317 s->matrix, s->intOpacity);
2322 bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
2323 bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
2324 if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
2325 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2327 QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
2329 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2331 }
else if (clip->hasRectClip) {
2332 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2337 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2338 if (func && (!clip || clip->hasRectClip)) {
2339 QRectF tr = qt_mapRect_non_normalizing(r, s->matrix);
2340 if (!s->flags.antialiased) {
2341 tr.setX(qRound(tr.x()));
2342 tr.setY(qRound(tr.y()));
2343 tr.setWidth(qRound(tr.width()));
2344 tr.setHeight(qRound(tr.height()));
2346 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2347 img.bits(), img.bytesPerLine(), img.height(),
2349 !clip ? d->deviceRect : clip->clipRect,
2356 QTransform copy = s->matrix;
2357 copy.translate(r.x(), r.y());
2359 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2360 copy.translate(-sr.x(), -sr.y());
2362 d->image_filler_xform.clip = clip;
2363 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2364 if (!d->image_filler_xform.blend)
2366 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2368 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2369 QRectF rr = s->matrix.mapRect(r);
2371 const int x1 = qRound(rr.x());
2372 const int y1 = qRound(rr.y());
2373 const int x2 = qRound(rr.right());
2374 const int y2 = qRound(rr.bottom());
2376 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2381 ensureRasterState();
2382 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2383 d->initializeRasterizer(&d->image_filler_xform);
2384 d->rasterizer->setAntialiased(s->flags.antialiased);
2386 const QRectF &rect = r.normalized();
2387 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2388 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2390 if (s->flags.tx_noshear)
2391 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2393 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2399 QTransform m = s->matrix;
2400 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2401 m.m21(), m.m22(), m.m23(),
2402 m.m31(), m.m32(), m.m33());
2403 fillPath(path, &d->image_filler_xform);
2406 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2407 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, sr)) {
2409 d->blitImage(pt, img, d->deviceRect, sr.toRect());
2411 }
else if (clip->hasRectClip) {
2412 d->blitImage(pt, img, clip->clipRect, sr.toRect());
2415 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2416 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2419 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2421 }
else if (clip->hasRectClip) {
2422 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2428 d->image_filler.clip = clip;
2429 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2430 if (!d->image_filler.blend)
2432 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2433 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2436 rr.translate(s->matrix.dx(), s->matrix.dy());
2438 const int x1 = qRound(rr.x());
2439 const int y1 = qRound(rr.y());
2440 const int x2 = qRound(rr.right());
2441 const int y2 = qRound(rr.bottom());
2443 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2448
2449
2450void QRasterPaintEngine::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sr)
2453 qDebug() <<
" - QRasterPaintEngine::drawTiledPixmap(), r=" << r <<
"pixmap=" << pixmap.size();
2455 Q_D(QRasterPaintEngine);
2456 QRasterPaintEngineState *s = state();
2461 QPlatformPixmap *pd = pixmap.handle();
2462 if (pd->classId() == QPlatformPixmap::RasterClass) {
2463 image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2465 image = pixmap.toImage();
2468 if (image.depth() == 1)
2469 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2471 const qreal pixmapDevicePixelRatio = pixmap.devicePixelRatio();
2472 if (s->matrix.type() > QTransform::TxTranslate || pixmapDevicePixelRatio > qreal(1.0)) {
2473 QTransform copy = s->matrix;
2474 copy.translate(r.x(), r.y());
2475 copy.translate(-sr.x(), -sr.y());
2476 const qreal inverseDpr = qreal(1.0) / pixmapDevicePixelRatio;
2477 copy.scale(inverseDpr, inverseDpr);
2478 d->image_filler_xform.clip = d->clip();
2479 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2480 if (!d->image_filler_xform.blend)
2482 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2485 ensureRasterState();
2486 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2487 d->initializeRasterizer(&d->image_filler_xform);
2488 d->rasterizer->setAntialiased(s->flags.antialiased);
2490 const QRectF &rect = r.normalized();
2491 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2492 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2493 if (s->flags.tx_noshear)
2494 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2496 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2502 fillPath(path, &d->image_filler_xform);
2504 d->image_filler.clip = d->clip();
2506 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2507 if (!d->image_filler.blend)
2509 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2510 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2513 rr.translate(s->matrix.dx(), s->matrix.dy());
2514 fillRect_normalized(rr.normalized().toRect(), &d->image_filler, d);
2522 return (s[x>>3] << (x&7)) & 0x80;
2526
2527
2528QRasterBuffer *QRasterPaintEngine::rasterBuffer()
2530 Q_D(QRasterPaintEngine);
2531 return d->rasterBuffer.data();
2535
2536
2537void QRasterPaintEngine::alphaPenBlt(
const void* src,
int bpl,
int depth,
int rx,
int ry,
int w,
int h,
bool useGammaCorrection)
2539 Q_D(QRasterPaintEngine);
2540 QRasterPaintEngineState *s = state();
2542 if (!s->penData.blend)
2545 QRasterBuffer *rb = d->rasterBuffer.data();
2546 if (rb->colorSpace.transferFunction() == QColorSpace::TransferFunction::Linear)
2547 useGammaCorrection =
false;
2549 const QRect rect(rx, ry, w, h);
2550 const QClipData *clip = d->clip();
2551 bool unclipped =
false;
2554 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2555 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2557 if (clip->hasRectClip) {
2558 unclipped = rx > clip->xmin
2559 && rx + w < clip->xmax
2561 && ry + h < clip->ymax;
2568 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2569 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2574 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2575 && rect.top() >= 0 && rect.bottom() < rb->height();
2577 unclipped = contains && d->isUnclipped_normalized(rect);
2580 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2581 const uchar * scanline =
static_cast<
const uchar *>(src);
2583 if (s->flags.fast_text) {
2586 if (s->penData.bitmapBlit) {
2587 s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2588 scanline, w, h, bpl);
2591 }
else if (depth == 8) {
2592 if (s->penData.alphamapBlit) {
2593 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2594 scanline, w, h, bpl,
nullptr, useGammaCorrection);
2597 }
else if (depth == 32) {
2599 if (s->penData.alphaRGBBlit) {
2600 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2601 (
const uint *) scanline, w, h, bpl / 4,
nullptr, useGammaCorrection);
2605 }
else if ((depth == 8 && s->penData.alphamapBlit) || (depth == 32 && s->penData.alphaRGBBlit)) {
2608 int nx = qMax(0, rx);
2609 int ny = qMax(0, ry);
2612 int xdiff = nx - rx;
2613 int ydiff = ny - ry;
2614 scanline += ydiff * bpl;
2615 scanline += xdiff * (depth == 32 ? 4 : 1);
2620 if (nx + w > d->rasterBuffer->width())
2621 w = d->rasterBuffer->width() - nx;
2622 if (ny + h > d->rasterBuffer->height())
2623 h = d->rasterBuffer->height() - ny;
2629 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2630 scanline, w, h, bpl, clip, useGammaCorrection);
2631 else if (depth == 32)
2632 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2633 (
const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
2647 scanline += bpl * y0;
2651 w = qMin(w, rb->width() - qMax(0, rx));
2652 h = qMin(h, rb->height() - qMax(0, ry));
2654 if (w <= 0 || h <= 0)
2657 const int NSPANS = 512;
2658 QT_FT_Span spans[NSPANS];
2661 const int x1 = x0 + w;
2662 const int y1 = y0 + h;
2665 for (
int y = y0; y < y1; ++y) {
2666 for (
int x = x0; x < x1; ) {
2667 if (!monoVal(scanline, x)) {
2672 if (current == NSPANS) {
2673 blend(current, spans, &s->penData);
2676 spans[current].x = x + rx;
2677 spans[current].y = y + ry;
2678 spans[current].coverage = 255;
2682 while (x < x1 && monoVal(scanline, x)) {
2686 spans[current].len = len;
2691 }
else if (depth == 8) {
2692 for (
int y = y0; y < y1; ++y) {
2693 for (
int x = x0; x < x1; ) {
2695 if (scanline[x] == 0) {
2700 if (current == NSPANS) {
2701 blend(current, spans, &s->penData);
2704 int coverage = scanline[x];
2705 spans[current].x = x + rx;
2706 spans[current].y = y + ry;
2707 spans[current].coverage = coverage;
2712 while (x < x1 && scanline[x] == coverage) {
2716 spans[current].len = len;
2722 const uint *sl = (
const uint *) scanline;
2723 for (
int y = y0; y < y1; ++y) {
2724 for (
int x = x0; x < x1; ) {
2726 if ((sl[x] & 0x00ffffff) == 0) {
2731 if (current == NSPANS) {
2732 blend(current, spans, &s->penData);
2735 uint rgbCoverage = sl[x];
2736 int coverage = qGreen(rgbCoverage);
2737 spans[current].x = x + rx;
2738 spans[current].y = y + ry;
2739 spans[current].coverage = coverage;
2744 while (x < x1 && sl[x] == rgbCoverage) {
2748 spans[current].len = len;
2751 sl += bpl /
sizeof(uint);
2758 blend(current, spans, &s->penData);
2762
2763
2764bool QRasterPaintEngine::drawCachedGlyphs(
int numGlyphs,
const glyph_t *glyphs,
2765 const QFixedPoint *positions, QFontEngine *fontEngine)
2767 Q_D(QRasterPaintEngine);
2768 QRasterPaintEngineState *s = state();
2770 bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
2771 && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
2773 if (fontEngine->hasInternalCaching()) {
2774 QFontEngine::GlyphFormat neededFormat =
2775 painter()->device()->devType() == QInternal::Widget
2776 ? QFontEngine::Format_None
2777 : QFontEngine::Format_A8;
2779 if (d_func()->mono_surface)
2780 neededFormat = QFontEngine::Format_Mono;
2782 for (
int i = 0; i < numGlyphs; i++) {
2783 QFixedPoint spp = fontEngine->subPixelPositionFor(positions[i]);
2784 if (!verticalSubPixelPositions)
2787 const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
2793 switch (alphaMap->format) {
2794 case QFontEngine::Format_Mono:
2796 bytesPerLine = ((alphaMap->width + 31) & ~31) >> 3;
2798 case QFontEngine::Format_A8:
2800 bytesPerLine = (alphaMap->width + 3) & ~3;
2802 case QFontEngine::Format_A32:
2804 bytesPerLine = alphaMap->width * 4;
2810 QFixed y = verticalSubPixelPositions
2811 ? qFloor(positions[i].y)
2812 : qRound(positions[i].y);
2814 alphaPenBlt(alphaMap->data, bytesPerLine, depth,
2815 qFloor(positions[i].x) + alphaMap->x,
2816 qFloor(y) - alphaMap->y,
2817 alphaMap->width, alphaMap->height,
2818 fontEngine->expectsGammaCorrectedBlending(QFontEngine::GlyphFormat(alphaMap->format)));
2822 QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
2824 QImageTextureGlyphCache *cache =
2825 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(
nullptr, glyphFormat, s->matrix, s->penData.solidColor));
2827 cache =
new QImageTextureGlyphCache(glyphFormat, s->matrix, s->penData.solidColor);
2828 fontEngine->setGlyphCache(
nullptr, cache);
2831 cache->populate(fontEngine, numGlyphs, glyphs, positions, s->renderHints);
2832 cache->fillInPendingGlyphs();
2834 const QImage &image = cache->image();
2835 qsizetype bpl = image.bytesPerLine();
2837 int depth = image.depth();
2842 else if (depth == 1)
2845 int margin = fontEngine->glyphMargin(glyphFormat);
2846 const uchar *bits = image.bits();
2847 for (
int i=0; i<numGlyphs; ++i) {
2848 QFixedPoint subPixelPosition = fontEngine->subPixelPositionFor(positions[i]);
2849 if (!verticalSubPixelPositions)
2850 subPixelPosition.y = 0;
2852 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2853 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2857 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2858 int y = (verticalSubPixelPositions
2859 ? qFloor(positions[i].y)
2860 : qRound(positions[i].y));
2861 y -= c.baseLineY + margin;
2871 const uchar *glyphBits = bits + ((c.x << leftShift) >> rightShift) + c.y * bpl;
2873 if (glyphFormat == QFontEngine::Format_ARGB) {
2877 QTransform originalTransform = s->matrix;
2878 s->matrix = QTransform();
2879 drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format()));
2880 s->matrix = originalTransform;
2882 alphaPenBlt(glyphBits,
2889 fontEngine->expectsGammaCorrectedBlending(glyphFormat));
2898
2899
2900
2901
2907 const QRect &r1 = deviceRect;
2908 return (r.left() >= r1.left() && r.right() <= r1.right()
2909 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2915 if (cl->clipRect == deviceRect)
2919 const QRect &r1 = cl->clipRect;
2920 return (r.left() >= r1.left() && r.right() <= r1.right()
2921 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2923 return qt_region_strictContains(cl->clipRegion, r);
2930 Q_Q(
const QRasterPaintEngine);
2933 QRect r = rect.normalized();
2936 const QRect &r1 = deviceRect;
2937 return (r.left() >= r1.left() && r.right() <= r1.right()
2938 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2943 if (cl->hasRectClip && cl->clipRect == deviceRect)
2950 r.setX(r.x() - penWidth);
2951 r.setY(r.y() - penWidth);
2952 r.setWidth(r.width() + 2 * penWidth);
2953 r.setHeight(r.height() + 2 * penWidth);
2958 const QRect &r1 = cl->clipRect;
2959 return (r.left() >= r1.left() && r.right() <= r1.right()
2960 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2962 return qt_region_strictContains(cl->clipRegion, r);
2969 const QRectF norm = rect.normalized();
2970 if (norm.left() <= qreal(INT_MIN) || norm.top() <= qreal(INT_MIN)
2971 || norm.right() > qreal(INT_MAX) || norm.bottom() > qreal(INT_MAX)
2972 || norm.width() > qreal(INT_MAX) || norm.height() > qreal(INT_MAX))
2974 return isUnclipped(norm.toAlignedRect(), penWidth);
2979 const QSpanData *data)
const
2981 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2986 const QSpanData *data)
const
2988 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2993 const QSpanData *data)
const
2995 Q_Q(
const QRasterPaintEngine);
2998 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3001 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3011 glyph_t *glyphs, QFixedPoint *positions,
int numGlyphs)
3013 QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
3014 QFixed clipRight = QFixed::fromReal(clip.right() + 1);
3015 QFixed clipTop = QFixed::fromReal(clip.top() - 1);
3016 QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
3019 while (first < numGlyphs) {
3020 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
3021 QFixed left = metrics.x + positions[first].x;
3022 QFixed top = metrics.y + positions[first].y;
3023 QFixed right = left + metrics.width;
3024 QFixed bottom = top + metrics.height;
3025 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3029 int last = numGlyphs - 1;
3030 while (last > first) {
3031 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
3032 QFixed left = metrics.x + positions[last].x;
3033 QFixed top = metrics.y + positions[last].y;
3034 QFixed right = left + metrics.width;
3035 QFixed bottom = top + metrics.height;
3036 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3040 return {first, last + 1};
3044
3045
3046void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3048 if (textItem->numGlyphs == 0)
3052 ensureRasterState();
3054 QTransform matrix = state()->matrix;
3056 QFontEngine *fontEngine = textItem->fontEngine();
3057 if (shouldDrawCachedGlyphs(fontEngine, matrix)) {
3058 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3060 }
else if (matrix.type() < QTransform::TxProject) {
3062 QTransform invMat = matrix.inverted(&invertible);
3066 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3067 textItem->fontEngine(), textItem->glyphs,
3068 textItem->glyphPositions, textItem->numGlyphs);
3069 QStaticTextItem copy = *textItem;
3070 copy.glyphs += range.begin;
3071 copy.glyphPositions += range.begin;
3072 copy.numGlyphs = range.end - range.begin;
3073 QPaintEngineEx::drawStaticTextItem(©);
3075 QPaintEngineEx::drawStaticTextItem(textItem);
3080
3081
3082void QRasterPaintEngine::drawTextItem(
const QPointF &p,
const QTextItem &textItem)
3084 const QTextItemInt &ti =
static_cast<
const QTextItemInt &>(textItem);
3087 Q_D(QRasterPaintEngine);
3088 fprintf(stderr,
" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3089 p.x(), p.y(), QStringView(ti.chars, ti.num_chars).toLatin1().data(),
3090 d->glyphCacheFormat);
3093 if (ti.glyphs.numGlyphs == 0)
3096 ensureRasterState();
3098 QRasterPaintEngineState *s = state();
3099 QTransform matrix = s->matrix;
3101 if (shouldDrawCachedGlyphs(ti.fontEngine, matrix)) {
3102 QVarLengthArray<QFixedPoint> positions;
3103 QVarLengthArray<glyph_t> glyphs;
3105 matrix.translate(p.x(), p.y());
3106 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3108 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3109 }
else if (matrix.type() < QTransform::TxProject
3110 && ti.fontEngine->supportsTransformation(matrix)) {
3112 QTransform invMat = matrix.inverted(&invertible);
3116 QVarLengthArray<QFixedPoint> positions;
3117 QVarLengthArray<glyph_t> glyphs;
3119 ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3120 ti.flags, glyphs, positions);
3121 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3122 ti.fontEngine, glyphs.data(), positions.data(),
3125 if (range.begin >= range.end)
3128 QStaticTextItem staticTextItem;
3129 staticTextItem.color = s->pen.color();
3130 staticTextItem.font = s->font;
3131 staticTextItem.setFontEngine(ti.fontEngine);
3132 staticTextItem.numGlyphs = range.end - range.begin;
3133 staticTextItem.glyphs = glyphs.data() + range.begin;
3134 staticTextItem.glyphPositions = positions.data() + range.begin;
3135 QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3137 QPaintEngineEx::drawTextItem(p, ti);
3142
3143
3144void QRasterPaintEngine::drawPoints(
const QPointF *points,
int pointCount)
3146 Q_D(QRasterPaintEngine);
3147 QRasterPaintEngineState *s = state();
3150 if (!s->penData.blend)
3153 if (!s->flags.fast_pen) {
3154 QPaintEngineEx::drawPoints(points, pointCount);
3158 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3159 stroker.drawPoints(points, pointCount);
3163void QRasterPaintEngine::drawPoints(
const QPoint *points,
int pointCount)
3165 Q_D(QRasterPaintEngine);
3166 QRasterPaintEngineState *s = state();
3169 if (!s->penData.blend)
3172 if (!s->flags.fast_pen) {
3173 QPaintEngineEx::drawPoints(points, pointCount);
3177 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3178 stroker.drawPoints(points, pointCount);
3182
3183
3184void QRasterPaintEngine::drawLines(
const QLine *lines,
int lineCount)
3187 qDebug() <<
" - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3189 Q_D(QRasterPaintEngine);
3190 QRasterPaintEngineState *s = state();
3193 if (!s->penData.blend)
3196 if (s->flags.fast_pen) {
3197 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3198 for (
int i=0; i<lineCount; ++i) {
3199 const QLine &l = lines[i];
3200 stroker.drawLine(l.p1(), l.p2());
3203 QPaintEngineEx::drawLines(lines, lineCount);
3213 Q_Q(QRasterPaintEngine);
3216 const QPen &pen = s->lastPen;
3217 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3218 const QList<qreal> pattern = pen.dashPattern();
3220 qreal patternLength = 0;
3221 for (
int i = 0; i < pattern.size(); ++i)
3222 patternLength += pattern.at(i);
3224 if (patternLength <= 0)
3227 qreal length = line.length();
3228 Q_ASSERT(length > 0);
3229 if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
3230 rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
3234 while (length > 0) {
3235 const bool rasterize = *inDash;
3236 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3239 if (dash >= length) {
3240 dash = line.length();
3241 *dashOffset += dash / width;
3245 *inDash = !(*inDash);
3246 if (++*dashIndex >= pattern.size())
3253 if (rasterize && dash > 0)
3254 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3259
3260
3261void QRasterPaintEngine::drawLines(
const QLineF *lines,
int lineCount)
3264 qDebug() <<
" - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3266 Q_D(QRasterPaintEngine);
3267 QRasterPaintEngineState *s = state();
3270 if (!s->penData.blend)
3272 if (s->flags.fast_pen) {
3273 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3274 for (
int i=0; i<lineCount; ++i) {
3275 QLineF line = lines[i];
3276 stroker.drawLine(line.p1(), line.p2());
3279 QPaintEngineEx::drawLines(lines, lineCount);
3285
3286
3287void QRasterPaintEngine::drawEllipse(
const QRectF &rect)
3289 Q_D(QRasterPaintEngine);
3290 QRasterPaintEngineState *s = state();
3293 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3294 || (qpen_style(s->lastPen) == Qt::NoPen))
3295 && !s->flags.antialiased
3296 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3298 && s->matrix.type() <= QTransform::TxScale)
3301 const QRectF r = s->matrix.mapRect(rect);
3302 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3303 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3304 const QRect brect = QRect(
int(r.x()),
int(r.y()),
3308 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3309 &s->penData, &s->brushData);
3313 QPaintEngineEx::drawEllipse(rect);
3319
3320
3321void QRasterPaintEngine::setDC(HDC hdc) {
3322 Q_D(QRasterPaintEngine);
3327
3328
3329HDC QRasterPaintEngine::getDC()
const
3331 Q_D(
const QRasterPaintEngine);
3336
3337
3338void QRasterPaintEngine::releaseDC(HDC)
const
3345
3346
3347bool QRasterPaintEngine::requiresPretransformedGlyphPositions(QFontEngine *fontEngine,
const QTransform &m)
const
3350 if (shouldDrawCachedGlyphs(fontEngine, m))
3354 return QPaintEngineEx::requiresPretransformedGlyphPositions(fontEngine, m);
3358
3359
3360
3361bool QRasterPaintEngine::shouldDrawCachedGlyphs(QFontEngine *fontEngine,
const QTransform &m)
const
3364 if (m.type() >= QTransform::TxProject)
3372 if (!fontEngine->hasInternalCaching() && !fontEngine->supportsTransformation(m))
3375 if (fontEngine->supportsTransformation(m) && !fontEngine->isSmoothlyScalable)
3378 return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, m);
3382
3383
3384QPoint QRasterPaintEngine::coordinateOffset()
const
3386 return QPoint(0, 0);
3389void QRasterPaintEngine::drawBitmap(
const QPointF &pos,
const QImage &image, QSpanData *fg)
3394 Q_D(QRasterPaintEngine);
3396 Q_ASSERT(image.depth() == 1);
3398 const int spanCount = 512;
3399 QT_FT_Span spans[spanCount];
3403 int w = image.width();
3404 int h = image.height();
3405 int px = qRound(pos.x());
3406 int py = qRound(pos.y());
3407 int ymax = qMin(py + h, d->rasterBuffer->height());
3408 int ymin = qMax(py, 0);
3409 int xmax = qMin(px + w, d->rasterBuffer->width());
3410 int xmin = qMax(px, 0);
3412 int x_offset = xmin - px;
3414 QImage::Format format = image.format();
3415 for (
int y = ymin; y < ymax; ++y) {
3416 const uchar *src = image.scanLine(y - py);
3417 if (format == QImage::Format_MonoLSB) {
3418 for (
int x = 0; x < xmax - xmin; ++x) {
3419 int src_x = x + x_offset;
3420 uchar pixel = src[src_x >> 3];
3425 if (pixel & (0x1 << (src_x & 7))) {
3426 spans[n].x = xmin + x;
3428 spans[n].coverage = 255;
3430 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3434 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3437 if (n == spanCount) {
3438 fg->blend(n, spans, fg);
3444 for (
int x = 0; x < xmax - xmin; ++x) {
3445 int src_x = x + x_offset;
3446 uchar pixel = src[src_x >> 3];
3451 if (pixel & (0x80 >> (x & 7))) {
3452 spans[n].x = xmin + x;
3454 spans[n].coverage = 255;
3456 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3460 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3463 if (n == spanCount) {
3464 fg->blend(n, spans, fg);
3472 fg->blend(n, spans, fg);
3478
3479
3480
3481
3482
3483
3486
3487
3488
3489QRasterPaintEngine::ClipType QRasterPaintEngine::clipType()
const
3491 Q_D(
const QRasterPaintEngine);
3493 const QClipData *clip = d->clip();
3494 if (!clip || clip->hasRectClip)
3501
3502
3503
3504QRectF QRasterPaintEngine::clipBoundingRect()
const
3506 Q_D(
const QRasterPaintEngine);
3508 const QClipData *clip = d->clip();
3511 return d->deviceRect;
3513 if (clip->hasRectClip)
3514 return clip->clipRect;
3516 return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3521 Q_Q(QRasterPaintEngine);
3524 rasterizer->setAntialiased(s->flags.antialiased);
3526 QRect clipRect(deviceRect);
3534 clipRect = clipRect.intersected(r);
3535 blend = data->blend;
3537 blend = data->unclipped_blend;
3540 rasterizer->setClipRect(clipRect);
3541 rasterizer->initialize(blend, data);
3545 ProcessSpans callback,
3548 if (!callback || !outline)
3551 Q_Q(QRasterPaintEngine);
3555 initializeRasterizer(spanData);
3557 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3561 rasterizer->rasterize(outline, fillRule);
3565 rasterize(outline, callback, (
void *)spanData, rasterBuffer);
3574 return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3578 ProcessSpans callback,
3581 if (!callback || !outline)
3584 Q_Q(QRasterPaintEngine);
3588 rasterizer->setAntialiased(s->flags.antialiased);
3589 rasterizer->setClipRect(deviceRect);
3590 rasterizer->initialize(callback, userData);
3592 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3596 rasterizer->rasterize(outline, fillRule);
3604 int rasterPoolSize = MINIMUM_POOL_SIZE;
3605 Q_DECL_UNINITIALIZED uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3606 uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3607 uchar *rasterPoolOnHeap =
nullptr;
3609 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3611 void *data = userData;
3613 QT_FT_BBox clip_box = { deviceRect.x(),
3615 deviceRect.x() + deviceRect.width(),
3616 deviceRect.y() + deviceRect.height() };
3618 QT_FT_Raster_Params rasterParams;
3619 rasterParams.target =
nullptr;
3620 rasterParams.source = outline;
3621 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3622 rasterParams.gray_spans =
nullptr;
3623 rasterParams.black_spans =
nullptr;
3624 rasterParams.bit_test =
nullptr;
3625 rasterParams.bit_set =
nullptr;
3626 rasterParams.user = data;
3627 rasterParams.clip_box = clip_box;
3632 int rendered_spans = 0;
3636 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3637 rasterParams.gray_spans = callback;
3638 rasterParams.skip_spans = rendered_spans;
3639 error = QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_render(*grayRaster.data(), &rasterParams);
3643 rasterPoolSize *= 2;
3644 if (rasterPoolSize > 1024 * 1024) {
3645 qWarning(
"QPainter: Rasterization of primitive failed");
3649 rendered_spans += QT_MANGLE_NAMESPACE(q_gray_rendered_spans)(*grayRaster.data());
3651 free(rasterPoolOnHeap);
3652 rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3654 Q_CHECK_PTR(rasterPoolOnHeap);
3656 rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3658 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*grayRaster.data());
3659 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(grayRaster.data());
3660 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3666 free(rasterPoolOnHeap);
3671 Q_Q(QRasterPaintEngine);
3674 if (!s->clipEnabled)
3678 replayClipOperations();
3683 Q_Q(QRasterPaintEngine);
3686 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3687 && s->matrix.type() <= QTransform::TxShear;
3692 Q_Q(
const QRasterPaintEngine);
3695 return s->flags.fast_images
3696 && (mode == QPainter::CompositionMode_SourceOver
3697 || (mode == QPainter::CompositionMode_Source
3698 && !image.hasAlphaChannel()));
3703 Q_Q(
const QRasterPaintEngine);
3705 if (!(mode == QPainter::CompositionMode_Source
3706 || (mode == QPainter::CompositionMode_SourceOver
3707 && !image.hasAlphaChannel())))
3711 Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
3713 if (s->intOpacity != 256
3714 || image.depth() < 8
3715 || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
3716 && (!isPixelAligned(pt) || !isPixelAligned(sr))))
3719 QImage::Format dFormat = rasterBuffer->format;
3720 QImage::Format sFormat = image.format();
3722 if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
3723 dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
3724 return (dFormat == sFormat);
3729 Q_ASSERT(image.depth() == 1);
3731 const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3732 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3733 if (sourceImage.isNull() || dest.isNull())
3736 QRgb fg = qPremultiply(color.rgba());
3739 int height = sourceImage.height();
3740 int width = sourceImage.width();
3741 for (
int y=0; y<height; ++y) {
3742 const uchar *source = sourceImage.constScanLine(y);
3743 QRgb *target =
reinterpret_cast<QRgb *>(dest.scanLine(y));
3744 for (
int x=0; x < width; ++x)
3745 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3756 compositionMode = QPainter::CompositionMode_SourceOver;
3764 m_buffer = (uchar *)image->bits();
3767 bytes_per_pixel = image->depth()/8;
3768 bytes_per_line = image->bytesPerLine();
3770 format = image->format();
3771 colorSpace = image->colorSpace();
3772 if (image->depth() == 1 && image->colorTable().size() == 2) {
3774 const QList<QRgb> colorTable = image->colorTable();
3775 destColor0 = qPremultiply(colorTable[0]);
3776 destColor1 = qPremultiply(colorTable[1]);
3785 m_clipLines =
nullptr;
3810 m_clipLines = (ClipLine *)calloc(clipSpanHeight,
sizeof(ClipLine));
3812 Q_CHECK_PTR(m_clipLines);
3814 allocated = clipSpanHeight;
3817 if (hasRegionClip) {
3818 const auto rects = clipRegion.begin();
3819 const int numRects = clipRegion.rectCount();
3820 const int maxSpans = (ymax - ymin) * numRects;
3821 allocated = qMax(allocated, maxSpans);
3822 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3823 Q_CHECK_PTR(m_spans);
3826 int firstInBand = 0;
3827 while (firstInBand < numRects) {
3828 const int currMinY = rects[firstInBand].y();
3829 const int currMaxY = currMinY + rects[firstInBand].height();
3831 while (y < currMinY) {
3832 m_clipLines[y].spans =
nullptr;
3833 m_clipLines[y].count = 0;
3837 int lastInBand = firstInBand;
3838 while (lastInBand + 1 < numRects && rects[lastInBand+1].top() == y)
3841 while (y < currMaxY) {
3843 m_clipLines[y].spans = m_spans + count;
3844 m_clipLines[y].count = lastInBand - firstInBand + 1;
3846 for (
int r = firstInBand; r <= lastInBand; ++r) {
3847 const QRect &currRect = rects[r];
3848 QT_FT_Span *span = m_spans + count;
3849 span->x = currRect.x();
3850 span->len = currRect.width();
3852 span->coverage = 255;
3858 firstInBand = lastInBand + 1;
3861 Q_ASSERT(count <= allocated);
3863 while (y < clipSpanHeight) {
3864 m_clipLines[y].spans =
nullptr;
3865 m_clipLines[y].count = 0;
3872 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3873 Q_CHECK_PTR(m_spans);
3878 m_clipLines[y].spans =
nullptr;
3879 m_clipLines[y].count = 0;
3883 const int len = clipRect.width();
3885 QT_FT_Span *span = m_spans + count;
3889 span->coverage = 255;
3892 m_clipLines[y].spans = span;
3893 m_clipLines[y].count = 1;
3897 while (y < clipSpanHeight) {
3898 m_clipLines[y].spans =
nullptr;
3899 m_clipLines[y].count = 0;
3910 m_clipLines =
nullptr;
3925 ymin = m_spans[0].y;
3926 ymax = m_spans[count-1].y + 1;
3930 const int firstLeft = m_spans[0].x;
3931 const int firstRight = m_spans[0].x + m_spans[0].len;
3934 for (
int i = 0; i <
count; ++i) {
3935 QT_FT_Span_& span = m_spans[i];
3938 if (span.y != y + 1 && y != -1)
3941 m_clipLines[y].spans = &span;
3942 m_clipLines[y]
.count = 1;
3946 const int spanLeft = span.x;
3947 const int spanRight = spanLeft + span.len;
3949 if (spanLeft <
xmin)
3952 if (spanRight >
xmax)
3955 if (spanLeft != firstLeft || spanRight != firstRight)
3961 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3966
3967
3970 if (hasRectClip && rect == clipRect)
3979 xmax = rect.x() + rect.width();
3992
3993
3996 if (region.rectCount() == 1) {
3997 setClipRect(region.boundingRect());
4003 clipRegion = region;
4006 const QRect rect = region.boundingRect();
4008 xmax = rect.x() + rect.width();
4010 ymax = rect.y() + rect.height();
4021
4022
4023
4025 const QT_FT_Span *spans,
const QT_FT_Span *end,
4026 QT_FT_Span **outSpans,
int available)
4030 QT_FT_Span *out = *outSpans;
4032 const QT_FT_Span *clipSpans = clip->m_spans + *currentClip;
4033 const QT_FT_Span *clipEnd = clip->m_spans + clip
->count;
4035 while (available && spans < end ) {
4036 if (clipSpans >= clipEnd) {
4040 if (clipSpans->y > spans->y) {
4044 if (spans->y != clipSpans->y) {
4045 if (spans->y < clip
->count && clip->m_clipLines[spans->y].spans)
4046 clipSpans = clip->m_clipLines[spans->y].spans;
4051 Q_ASSERT(spans->y == clipSpans->y);
4054 int sx2 = sx1 + spans->len;
4055 int cx1 = clipSpans->x;
4056 int cx2 = cx1 + clipSpans->len;
4058 if (cx1 < sx1 && cx2 < sx1) {
4061 }
else if (sx1 < cx1 && sx2 < cx1) {
4065 int x = qMax(sx1, cx1);
4066 int len = qMin(sx2, cx2) - x;
4068 out->x = qMax(sx1, cx1);
4069 out->len = qMin(sx2, cx2) - out->x;
4071 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4083 *currentClip = clipSpans - clip->m_spans;
4090 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4092 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4094 const int NSPANS = 512;
4095 Q_DECL_UNINITIALIZED QT_FT_Span cspans[NSPANS];
4096 int currentClip = 0;
4097 const QT_FT_Span *end = spans + spanCount;
4098 while (spans < end) {
4099 QT_FT_Span *clipped = cspans;
4100 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4104 if (clipped - cspans)
4105 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4110
4111
4112
4113
4117 const int minx = clip.left();
4118 const int miny = clip.top();
4119 const int maxx = clip.right();
4120 const int maxy = clip.bottom();
4122 QT_FT_Span *end = spans + numSpans;
4123 while (spans < end) {
4124 if (spans->y >= miny)
4129 QT_FT_Span *s = spans;
4133 if (s->x > maxx || s->x + s->len <= minx) {
4139 s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
4142 s->len = qMin(s->len, (maxx - s->x + 1));
4154 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4155 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4157 Q_ASSERT(fillData->clip);
4158 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4160 QT_FT_Span *s =
const_cast<QT_FT_Span *>(spans);
4162 count = qt_intersect_spans(s, count,
4163 fillData->clip->clipRect);
4165 fillData->unclipped_blend(count, s, fillData);
4168static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData)
4177 switch (clipData->operation) {
4179 case Qt::IntersectClip:
4184 int currentClip = 0;
4185 const QT_FT_Span *end = spans + count;
4186 while (spans < end) {
4187 QT_FT_Span *newspans = newClip->m_spans + newClip
->count;
4188 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4189 &newspans, newClip->allocated - newClip->count);
4190 newClip
->count = newspans - newClip->m_spans;
4192 newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 *
sizeof(QT_FT_Span)));
4199 case Qt::ReplaceClip:
4200 clipData
->newClip->appendSpans(spans, count);
4212 inline CacheInfo(QGradientStops s,
int op, QGradient::InterpolationMode mode) :
4224 quint64 hash_val = 0;
4226 const QGradientStops stops = gradient.stops();
4227 for (
int i = 0; i < stops.size() && i <= 2; i++)
4228 hash_val += stops[i].second.rgba64();
4230 QMutexLocker lock(&mutex);
4231 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4233 if (it == cache.constEnd())
4234 return addCacheElement(hash_val, gradient, opacity);
4237 const auto &cache_info = it.value();
4238 if (cache_info->stops == stops && cache_info->opacity == opacity && cache_info->interpolationMode == gradient.interpolationMode())
4241 }
while (it != cache.constEnd() && it.key() == hash_val);
4243 return addCacheElement(hash_val, gradient, opacity);
4251 QRgba64 *colorTable,
4252 int size,
int opacity)
const;
4254 if (cache.size() == maxCacheSize()) {
4256 cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize())));
4258 auto cache_entry =
std::make_shared<
CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode());
4259 generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
4260 for (
int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
4261 cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32();
4262 return cache.insert(hash_val, std::move(cache_entry)).value();
4271 const QGradientStops stops = gradient.stops();
4272 int stopCount = stops.size();
4273 Q_ASSERT(stopCount > 0);
4275 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4277 if (stopCount == 2) {
4278 QRgba64 first_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4279 QRgba64 second_color = combineAlpha256(stops[1].second.rgba64(), opacity);
4281 qreal first_stop = stops[0].first;
4282 qreal second_stop = stops[1].first;
4284 if (second_stop < first_stop) {
4285 quint64 tmp = first_color;
4286 first_color = second_color;
4288 qSwap(first_stop, second_stop);
4291 if (colorInterpolation) {
4292 first_color = qPremultiply(first_color);
4293 second_color = qPremultiply(second_color);
4296 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4297 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4299 uint red_first = uint(first_color.red()) << 16;
4300 uint green_first = uint(first_color.green()) << 16;
4301 uint blue_first = uint(first_color.blue()) << 16;
4302 uint alpha_first = uint(first_color.alpha()) << 16;
4304 uint red_second = uint(second_color.red()) << 16;
4305 uint green_second = uint(second_color.green()) << 16;
4306 uint blue_second = uint(second_color.blue()) << 16;
4307 uint alpha_second = uint(second_color.alpha()) << 16;
4310 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4311 if (colorInterpolation)
4312 colorTable[i] = first_color;
4314 colorTable[i] = qPremultiply(first_color);
4317 if (i < second_index) {
4318 qreal reciprocal = qreal(1) / (second_index - first_index);
4320 int red_delta = qRound((qreal(red_second) - red_first) * reciprocal);
4321 int green_delta = qRound((qreal(green_second) - green_first) * reciprocal);
4322 int blue_delta = qRound((qreal(blue_second) - blue_first) * reciprocal);
4323 int alpha_delta = qRound((qreal(alpha_second) - alpha_first) * reciprocal);
4326 red_first += 1 << 15;
4327 green_first += 1 << 15;
4328 blue_first += 1 << 15;
4329 alpha_first += 1 << 15;
4331 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4332 red_first += red_delta;
4333 green_first += green_delta;
4334 blue_first += blue_delta;
4335 alpha_first += alpha_delta;
4337 const QRgba64 color = qRgba64(red_first >> 16, green_first >> 16, blue_first >> 16, alpha_first >> 16);
4339 if (colorInterpolation)
4340 colorTable[i] = color;
4342 colorTable[i] = qPremultiply(color);
4346 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4347 if (colorInterpolation)
4348 colorTable[i] = second_color;
4350 colorTable[i] = qPremultiply(second_color);
4356 QRgba64 current_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4357 if (stopCount == 1) {
4358 current_color = qPremultiply(current_color);
4359 for (
int i = 0; i < size; ++i)
4360 colorTable[i] = current_color;
4365 qreal begin_pos = stops[0].first;
4366 qreal end_pos = stops[stopCount-1].first;
4371 qreal incr = 1 / qreal(size);
4372 qreal dpos = 1.5 * incr;
4375 colorTable[pos++] = qPremultiply(current_color);
4376 while (dpos <= begin_pos) {
4377 colorTable[pos] = colorTable[pos - 1];
4382 int current_stop = 0;
4387 if (dpos < end_pos) {
4389 while (dpos > stops[current_stop+1].first)
4392 if (current_stop != 0)
4393 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4394 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4396 if (colorInterpolation) {
4397 current_color = qPremultiply(current_color);
4398 next_color = qPremultiply(next_color);
4401 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4402 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4403 t = (dpos - stops[current_stop].first) * c;
4407 Q_ASSERT(current_stop < stopCount);
4409 int dist = qRound(t);
4410 int idist = 256 - dist;
4412 if (colorInterpolation)
4413 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
4415 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
4420 if (dpos >= end_pos)
4426 while (dpos > stops[current_stop+skip+1].first)
4430 current_stop += skip;
4432 current_color = next_color;
4434 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4435 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4437 if (colorInterpolation) {
4439 current_color = qPremultiply(current_color);
4440 next_color = qPremultiply(next_color);
4443 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4444 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4445 t = (dpos - stops[current_stop].first) * c;
4452 current_color = qPremultiply(combineAlpha256(stops[stopCount - 1].second.rgba64(), opacity));
4453 while (pos < size - 1) {
4454 colorTable[pos] = current_color;
4459 colorTable[size - 1] = current_color;
4465void QSpanData::init(QRasterBuffer *rb,
const QRasterPaintEngine *pe)
4471 m11 = m22 = m33 = 1.;
4472 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4473 clip = pe ? pe->d_func()->clip() :
nullptr;
4476Q_GUI_EXPORT
extern QImage qt_imageForBrush(
int brushStyle,
bool invert);
4478void QSpanData::setup(
const QBrush &brush,
int alpha, QPainter::CompositionMode compositionMode,
4481 Qt::BrushStyle brushStyle = qbrush_style(brush);
4482 cachedGradient.reset();
4483 switch (brushStyle) {
4484 case Qt::SolidPattern: {
4486 QColor c = qbrush_color(brush);
4487 solidColor = qPremultiplyWithExtraAlpha(c, alpha);
4488 if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
4493 case Qt::LinearGradientPattern:
4495 type = LinearGradient;
4496 const QLinearGradient *g =
static_cast<
const QLinearGradient *>(brush.gradient());
4497 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4499 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4500 gradient.colorTable32 = cacheInfo->buffer32;
4501#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4502 gradient.colorTable64 = cacheInfo->buffer64;
4504 cachedGradient = std::move(cacheInfo);
4506 gradient.spread = g->spread();
4508 QLinearGradientData &linearData = gradient.linear;
4510 linearData.origin.x = g->start().x();
4511 linearData.origin.y = g->start().y();
4512 linearData.end.x = g->finalStop().x();
4513 linearData.end.y = g->finalStop().y();
4517 case Qt::RadialGradientPattern:
4519 type = RadialGradient;
4520 const QRadialGradient *g =
static_cast<
const QRadialGradient *>(brush.gradient());
4521 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4523 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4524 gradient.colorTable32 = cacheInfo->buffer32;
4525#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4526 gradient.colorTable64 = cacheInfo->buffer64;
4528 cachedGradient = std::move(cacheInfo);
4530 gradient.spread = g->spread();
4532 QRadialGradientData &radialData = gradient.radial;
4534 QPointF center = g->center();
4535 radialData.center.x = center.x();
4536 radialData.center.y = center.y();
4537 radialData.center.radius = g->centerRadius();
4538 QPointF focal = g->focalPoint();
4539 radialData.focal.x = focal.x();
4540 radialData.focal.y = focal.y();
4541 radialData.focal.radius = g->focalRadius();
4545 case Qt::ConicalGradientPattern:
4547 type = ConicalGradient;
4548 const QConicalGradient *g =
static_cast<
const QConicalGradient *>(brush.gradient());
4549 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4551 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4552 gradient.colorTable32 = cacheInfo->buffer32;
4553#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4554 gradient.colorTable64 = cacheInfo->buffer64;
4556 cachedGradient = std::move(cacheInfo);
4558 gradient.spread = QGradient::RepeatSpread;
4560 QConicalGradientData &conicalData = gradient.conical;
4562 QPointF center = g->center();
4563 conicalData.center.x = center.x();
4564 conicalData.center.y = center.y();
4565 conicalData.angle = qDegreesToRadians(g->angle());
4569 case Qt::Dense1Pattern:
4570 case Qt::Dense2Pattern:
4571 case Qt::Dense3Pattern:
4572 case Qt::Dense4Pattern:
4573 case Qt::Dense5Pattern:
4574 case Qt::Dense6Pattern:
4575 case Qt::Dense7Pattern:
4576 case Qt::HorPattern:
4577 case Qt::VerPattern:
4578 case Qt::CrossPattern:
4579 case Qt::BDiagPattern:
4580 case Qt::FDiagPattern:
4581 case Qt::DiagCrossPattern:
4584 tempImage =
new QImage();
4585 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle,
true), brush.color());
4586 initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
4588 case Qt::TexturePattern:
4591 tempImage =
new QImage();
4593 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4594 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4596 *tempImage = brush.textureImage();
4597 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4605 adjustSpanMethods();
4608void QSpanData::adjustSpanMethods()
4610 bitmapBlit =
nullptr;
4611 alphamapBlit =
nullptr;
4612 alphaRGBBlit =
nullptr;
4618 unclipped_blend =
nullptr;
4621 const DrawHelper &drawHelper = qDrawHelper[rasterBuffer->format];
4622 unclipped_blend = drawHelper.blendColor;
4623 bitmapBlit = drawHelper.bitmapBlit;
4624 alphamapBlit = drawHelper.alphamapBlit;
4625 alphaRGBBlit = drawHelper.alphaRGBBlit;
4626 fillRect = drawHelper.fillRect;
4629 case LinearGradient:
4630 case RadialGradient:
4631 case ConicalGradient:
4632 unclipped_blend = qBlendGradient;
4635 unclipped_blend = qBlendTexture;
4636 if (!texture.imageData)
4637 unclipped_blend =
nullptr;
4642 if (!unclipped_blend) {
4645 blend = unclipped_blend;
4646 }
else if (clip->hasRectClip) {
4647 blend = clip->clipRect.isEmpty() ?
nullptr : qt_span_fill_clipRect;
4649 blend = qt_span_fill_clipped;
4653void QSpanData::setupMatrix(
const QTransform &matrix,
int bilin)
4657 delta.translate(1.0 / 65536, 1.0 / 65536);
4659 QTransform inv = (delta * matrix).inverted();
4672 const bool affine = inv.isAffine();
4673 const qreal f1 = m11 * m11 + m21 * m21;
4674 const qreal f2 = m12 * m12 + m22 * m22;
4675 fast_matrix = affine
4678 && f1 > (1.0 / 65536)
4679 && f2 > (1.0 / 65536)
4683 adjustSpanMethods();
4686void QSpanData::initTexture(
const QImage *image,
int alpha, QTextureData::Type _type,
const QRect &sourceRect)
4688 const QImageData *d =
const_cast<QImage *>(image)->data_ptr();
4689 if (!d || d->height == 0) {
4690 texture.imageData =
nullptr;
4697 texture.bytesPerLine = 0;
4698 texture.format = QImage::Format_Invalid;
4699 texture.colorTable =
nullptr;
4700 texture.hasAlpha = alpha != 256;
4702 texture.imageData = d->data;
4703 texture.width = d->width;
4704 texture.height = d->height;
4706 if (sourceRect.isNull()) {
4709 texture.x2 = texture.width;
4710 texture.y2 = texture.height;
4712 texture.x1 = sourceRect.x();
4713 texture.y1 = sourceRect.y();
4714 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4715 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4718 texture.bytesPerLine = d->bytes_per_line;
4720 texture.format = d->format;
4721 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable :
nullptr;
4722 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4724 texture.const_alpha = alpha;
4725 texture.type = _type;
4727 adjustSpanMethods();
4731
4732
4733
4737 ProcessSpans pen_func, ProcessSpans brush_func,
4738 QSpanData *pen_data, QSpanData *brush_data)
4743 QT_FT_Span _outline[4];
4744 QT_FT_Span *outline = _outline;
4745 const int midx = rect.x() + (rect.width() + 1) / 2;
4746 const int midy = rect.y() + (rect.height() + 1) / 2;
4752 outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4753 outline[0].len = qMin(length, x - outline[0].x);
4755 outline[0].coverage = 255;
4759 outline[1].len = length;
4761 outline[1].coverage = 255;
4764 outline[2].x = outline[0].x;
4765 outline[2].len = outline[0].len;
4766 outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4767 outline[2].coverage = 255;
4771 outline[3].len = length;
4772 outline[3].y = outline[2].y;
4773 outline[3].coverage = 255;
4775 if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4776 QT_FT_Span _fill[2];
4777 QT_FT_Span *fill = _fill;
4780 fill[0].x = outline[0].x + outline[0].len - 1;
4781 fill[0].len = qMax(0, outline[1].x - fill[0].x);
4782 fill[0].y = outline[1].y;
4783 fill[0].coverage = 255;
4786 fill[1].x = outline[2].x + outline[2].len - 1;
4787 fill[1].len = qMax(0, outline[3].x - fill[1].x);
4788 fill[1].y = outline[3].y;
4789 fill[1].coverage = 255;
4791 int n = (fill[0].y >= fill[1].y ? 1 : 2);
4792 n = qt_intersect_spans(fill, n, clip);
4794 brush_func(n, fill, brush_data);
4797 int n = (outline[1].y >= outline[2].y ? 2 : 4);
4798 n = qt_intersect_spans(outline, n, clip);
4800 pen_func(n, outline, pen_data);
4805
4806
4807
4809 ProcessSpans pen_func, ProcessSpans brush_func,
4810 QSpanData *pen_data, QSpanData *brush_data)
4812 const qreal a = qreal(rect.width()) / 2;
4813 const qreal b = qreal(rect.height()) / 2;
4814 qreal d = b*b - (a*a*b) + 0.25*a*a;
4817 int y = (rect.height() + 1) / 2;
4821 while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4826 d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4827 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4828 pen_func, brush_func, pen_data, brush_data);
4833 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4834 pen_func, brush_func, pen_data, brush_data);
4837 d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4838 const int miny = rect.height() & 0x1;
4841 d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4844 d += a*a*(-2*y + 3);
4847 drawEllipsePoints(x, y, 1, rect, clip,
4848 pen_func, brush_func, pen_data, brush_data);
4853
4854
4855
4856
4860void dumpClip(
int width,
int height,
const QClipData *clip)
4862 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4863 clipImg.fill(0xffff0000);
4870 ((QClipData *) clip)->spans();
4872 for (
int i = 0; i < clip->count; ++i) {
4873 const QT_FT_Span *span = ((QClipData *) clip)->spans() + i;
4874 for (
int j = 0; j < span->len; ++j)
4875 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4876 x0 = qMin(x0,
int(span->x));
4877 x1 = qMax(x1,
int(span->x + span->len - 1));
4879 y0 = qMin(y0,
int(span->y));
4880 y1 = qMax(y1,
int(span->y));
4883 static int counter = 0;
4890 fprintf(stderr,
"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4891 clipImg.save(QString::fromLatin1(
"clip-%0.png").arg(counter++));
void setClipRegion(const QRegion ®ion)
void setClipRect(const QRect &rect)
void generateGradientColorTable(const QGradient &g, QRgba64 *colorTable, int size, int opacity) const
QGradientColorTableHash cache
std::shared_ptr< const CacheInfo > addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity)
std::shared_ptr< const CacheInfo > getBuffer(const QGradient &gradient, int opacity)
bool monoDestinationWithClut
QImage::Format prepare(QImage *image)
QImage colorizeBitmap(const QImage &image, const QColor &color)
bool isUnclipped_normalized(const QRect &rect) const
void recalculateFastImages()
void initializeRasterizer(QSpanData *data)
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *rasterBuffer)
bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const
bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, const QRect &clip, int alpha, const QRect &sr=QRect())
bool isUnclipped(const QRect &rect, int penWidth) const
void rasterizeLine_dashed(QLineF line, qreal width, int *dashIndex, qreal *dashOffset, bool *inDash)
void blitImage(const QPointF &pt, const QImage &img, const QRect &clip, const QRect &sr=QRect())
const QClipData * clip() const
void systemStateChanged() override
void updateMatrixData(QSpanData *spanData, const QBrush &brush, const QTransform &brushMatrix)
void rasterize(QT_FT_Outline *outline, ProcessSpans callback, QSpanData *spanData, QRasterBuffer *rasterBuffer)
ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const
~QRasterPaintEngineState()
QRasterPaintEngineState(const QRasterPaintEngineState &other)
QRasterPaintEngineState()
QRectVectorPath(const QRect &r)
Combined button and popup list for selecting options.
void QT_MANGLE_NAMESPACE qt_startup_hook()
QT_BEGIN_NAMESPACE constexpr int QT_RASTER_COORD_LIMIT
@ LineDrawIncludeLastPixel
static int fast_ceil_positive(const qreal &v)
static void qt_span_fill_clipRect(int count, const QT_FT_Span *spans, void *userData)
static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data)
static void fillRect_normalized(const QRect &r, QSpanData *data, QRasterPaintEnginePrivate *pe)
static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
static const QT_FT_Span * qt_intersect_spans(const QClipData *clip, int *currentClip, const QT_FT_Span *spans, const QT_FT_Span *end, QT_FT_Span **outSpans, int available)
QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
static void qt_span_clip(int count, const QT_FT_Span *spans, void *userData)
static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
static VisibleGlyphRange visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
static bool monoVal(const uchar *s, int x)
static uchar * alignAddress(uchar *address, quintptr alignmentMask)
static bool splitPolygon(const QPointF *points, int pointCount, QList< QPointF > *upper, QList< QPointF > *lower)
static void drawEllipsePoints(int x, int y, int length, const QRect &rect, const QRect &clip, ProcessSpans pen_func, ProcessSpans brush_func, QSpanData *pen_data, QSpanData *brush_data)
static void qt_span_fill_clipped(int count, const QT_FT_Span *spans, void *userData)
static QColor qPremultiplyWithExtraAlpha(const QColor &c, int alpha)
static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)
#define int_dim(pos, dim)
static const QRect toAlignedRect_positive(const QRectF &rect)
static bool isAbove(const QPointF *a, const QPointF *b)
static int qt_intersect_spans(QT_FT_Span *&spans, int numSpans, const QRect &clip)
Qt::ClipOperation operation
QRgba64 buffer64[GRADIENT_STOPTABLE_SIZE]
QRgb buffer32[GRADIENT_STOPTABLE_SIZE]
CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode)
QGradient::InterpolationMode interpolationMode