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) {
1720 const QRect rr = toNormalizedFillRect(QRectF(s->matrix.map(r.topLeft()),
1721 s->matrix.map(r.bottomRight())));
1722 fillRect_normalized(rr, data, d);
1726 ensureRasterState();
1727 if (s->flags.tx_noshear) {
1728 d->initializeRasterizer(data);
1729 QRectF nr = r.normalized();
1730 if (!nr.isEmpty()) {
1731 const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1732 const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1733 d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1740 ensureOutlineMapper();
1741 fillPath(path, data);
1745
1746
1747void QRasterPaintEngine::fillRect(
const QRectF &r,
const QBrush &brush)
1750 qDebug() <<
"QRasterPaintEngine::fillRecct(): " << r << brush;
1752 QRasterPaintEngineState *s = state();
1755 if (!s->brushData.blend)
1758 fillRect(r, &s->brushData);
1764 return Qt::transparent;
1765 if (c.spec() == QColor::ExtendedRgb) {
1767 c.getRgbF(&r, &g, &b, &a);
1768 a = a * alpha * (1.f / 256.f);
1769 return QColor::fromRgbF(r * a, g * a, b * a, a);
1771 return qPremultiply(combineAlpha256(c.rgba64(), alpha));
1775
1776
1777void QRasterPaintEngine::fillRect(
const QRectF &r,
const QColor &color)
1780 qDebug() <<
"QRasterPaintEngine::fillRect(): " << r << color;
1782 Q_D(QRasterPaintEngine);
1783 QRasterPaintEngineState *s = state();
1785 d->solid_color_filler.solidColor = qPremultiplyWithExtraAlpha(color, s->intOpacity);
1787 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f
1788 && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1791 d->solid_color_filler.clip = d->clip();
1792 d->solid_color_filler.adjustSpanMethods();
1793 fillRect(r, &d->solid_color_filler);
1796static inline bool isAbove(
const QPointF *a,
const QPointF *b)
1798 return a->y() < b->y();
1801static bool splitPolygon(
const QPointF *points,
int pointCount, QList<QPointF> *upper, QList<QPointF> *lower)
1806 Q_ASSERT(pointCount >= 2);
1808 QList<
const QPointF *> sorted;
1809 sorted.reserve(pointCount);
1811 upper->reserve(pointCount * 3 / 4);
1812 lower->reserve(pointCount * 3 / 4);
1814 for (
int i = 0; i < pointCount; ++i)
1815 sorted << points + i;
1817 std::sort(sorted.begin(), sorted.end(), isAbove);
1819 qreal splitY = sorted.at(sorted.size() / 2)->y();
1821 const QPointF *end = points + pointCount;
1822 const QPointF *last = end - 1;
1824 QList<QPointF> *bin[2] = { upper, lower };
1826 for (
const QPointF *p = points; p < end; ++p) {
1827 int side = p->y() < splitY;
1828 int lastSide = last->y() < splitY;
1830 if (side != lastSide) {
1831 if (qFuzzyCompare(p->y(), splitY)) {
1832 bin[!side]->append(*p);
1833 }
else if (qFuzzyCompare(last->y(), splitY)) {
1834 bin[side]->append(*last);
1836 QPointF delta = *p - *last;
1837 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1839 bin[0]->append(intersection);
1840 bin[1]->append(intersection);
1844 bin[side]->append(*p);
1850 return upper->size() < pointCount && lower->size() < pointCount;
1854
1855
1856void QRasterPaintEngine::fillPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1858 Q_D(QRasterPaintEngine);
1859 QRasterPaintEngineState *s = state();
1861 const int maxPoints = 0xffff;
1864 if (pointCount > maxPoints) {
1865 QList<QPointF> upper, lower;
1867 if (splitPolygon(points, pointCount, &upper, &lower)) {
1868 fillPolygon(upper.constData(), upper.size(), mode);
1869 fillPolygon(lower.constData(), lower.size(), mode);
1871 qWarning(
"Polygon too complex for filling.");
1877 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1878 ensureOutlineMapper();
1879 QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1882 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1884 d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1888
1889
1890void QRasterPaintEngine::drawPolygon(
const QPointF *points,
int pointCount, PolygonDrawMode mode)
1892 Q_D(QRasterPaintEngine);
1893 QRasterPaintEngineState *s = state();
1896 qDebug(
" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1897 for (
int i=0; i<pointCount; ++i)
1898 qDebug() <<
" - " << points[i];
1900 Q_ASSERT(pointCount >= 2);
1902 if (mode != PolylineMode && QVectorPath::isRect((
const qreal *) points, pointCount)) {
1903 QRectF r(points[0], points[2]);
1909 if (mode != PolylineMode) {
1912 if (s->brushData.blend)
1913 fillPolygon(points, pointCount, mode);
1917 if (s->penData.blend) {
1918 QVectorPath vp((
const qreal *) points, pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1919 if (s->flags.fast_pen) {
1920 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1921 stroker.drawPath(vp);
1923 QPaintEngineEx::stroke(vp, s->lastPen);
1929
1930
1931void QRasterPaintEngine::drawPolygon(
const QPoint *points,
int pointCount, PolygonDrawMode mode)
1933 Q_D(QRasterPaintEngine);
1934 QRasterPaintEngineState *s = state();
1937 qDebug(
" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1938 for (
int i=0; i<pointCount; ++i)
1939 qDebug() <<
" - " << points[i];
1941 Q_ASSERT(pointCount >= 2);
1942 if (mode != PolylineMode && QVectorPath::isRect((
const int *) points, pointCount)) {
1943 QRect r(points[0].x(),
1945 points[2].x() - points[0].x(),
1946 points[2].y() - points[0].y());
1954 if (mode != PolylineMode) {
1956 if (s->brushData.blend) {
1958 ensureOutlineMapper();
1959 d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1960 d->outlineMapper->moveTo(*points);
1961 const QPoint *p = points;
1962 const QPoint *ep = points + pointCount - 1;
1964 d->outlineMapper->lineTo(*(++p));
1966 d->outlineMapper->endOutline();
1969 ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1971 d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
1976 if (s->penData.blend) {
1977 int count = pointCount * 2;
1978 QVarLengthArray<qreal> fpoints(count);
1979 for (
int i=0; i<count; ++i)
1980 fpoints[i] = ((
const int *) points)[i];
1981 QVectorPath vp((qreal *) fpoints.data(), pointCount,
nullptr, QVectorPath::polygonFlags(mode));
1983 if (s->flags.fast_pen) {
1984 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
1985 stroker.drawPath(vp);
1987 QPaintEngineEx::stroke(vp, s->lastPen);
1993
1994
1995void QRasterPaintEngine::drawPixmap(
const QPointF &pos,
const QPixmap &pixmap)
1998 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), pos=" << pos <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
2001 QPlatformPixmap *pd = pixmap.handle();
2002 if (pd->classId() == QPlatformPixmap::RasterClass) {
2003 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2004 if (image.depth() == 1) {
2005 Q_D(QRasterPaintEngine);
2006 QRasterPaintEngineState *s = state();
2007 if (s->matrix.type() <= QTransform::TxTranslate) {
2009 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2011 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2014 QRasterPaintEngine::drawImage(pos, image);
2017 const QImage image = pixmap.toImage();
2018 if (pixmap.depth() == 1) {
2019 Q_D(QRasterPaintEngine);
2020 QRasterPaintEngineState *s = state();
2021 if (s->matrix.type() <= QTransform::TxTranslate) {
2023 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2025 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2028 QRasterPaintEngine::drawImage(pos, image);
2034
2035
2036void QRasterPaintEngine::drawPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QRectF &sr)
2039 qDebug() <<
" - QRasterPaintEngine::drawPixmap(), r=" << r <<
" sr=" << sr <<
" pixmap=" << pixmap.size() <<
"depth=" << pixmap.depth();
2042 QPlatformPixmap* pd = pixmap.handle();
2043 if (pd->classId() == QPlatformPixmap::RasterClass) {
2044 const QImage &image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2045 if (image.depth() == 1) {
2046 Q_D(QRasterPaintEngine);
2047 QRasterPaintEngineState *s = state();
2048 if (s->matrix.type() <= QTransform::TxTranslate
2049 && r.size() == sr.size()
2050 && r.size() == pixmap.size()) {
2052 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2055 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2058 drawImage(r, image, sr);
2061 QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2062 const QImage image = pd->toImage(clippedSource);
2063 QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2064 if (image.depth() == 1) {
2065 Q_D(QRasterPaintEngine);
2066 QRasterPaintEngineState *s = state();
2067 if (s->matrix.type() <= QTransform::TxTranslate
2068 && r.size() == sr.size()
2069 && r.size() == pixmap.size()) {
2071 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2074 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2077 drawImage(r, image, translatedSource);
2084 const int iv =
int(v);
2093 const int xmin =
int(rect.x());
2094 const int xmax =
int(fast_ceil_positive(rect.right()));
2095 const int ymin =
int(rect.y());
2096 const int ymax =
int(fast_ceil_positive(rect.bottom()));
2097 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2101
2102
2103void QRasterPaintEngine::drawImage(
const QPointF &p,
const QImage &img)
2106 qDebug() <<
" - QRasterPaintEngine::drawImage(), p=" << p <<
" image=" << img.size() <<
"depth=" << img.depth();
2109 Q_D(QRasterPaintEngine);
2110 QRasterPaintEngineState *s = state();
2111 qreal scale = img.devicePixelRatio();
2113 if (scale > 1.0 || s->matrix.type() > QTransform::TxTranslate) {
2114 drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
2116 QRectF(0, 0, img.width(), img.height()));
2119 const QClipData *clip = d->clip();
2120 QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2122 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, img.rect())) {
2124 d->blitImage(pt, img, d->deviceRect);
2126 }
else if (clip->hasRectClip) {
2127 d->blitImage(pt, img, clip->clipRect);
2130 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2131 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2134 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2136 }
else if (clip->hasRectClip) {
2137 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2145 d->image_filler.clip = clip;
2146 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2147 if (!d->image_filler.blend)
2149 d->image_filler.dx = -pt.x();
2150 d->image_filler.dy = -pt.y();
2151 QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2153 fillRect_normalized(rr, &d->image_filler, d);
2160 return QRectF(r.topLeft() * t, r.bottomRight() * t);
2171 inline RotationType qRotationType(
const QTransform &transform)
2173 QTransform::TransformationType type = transform.type();
2175 if (type > QTransform::TxRotate)
2178 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2179 && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2182 if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2183 && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2186 if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2187 && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2193 inline bool isPixelAligned(
const QPointF &pt)
2195 return QPointF(pt.toPoint()) == pt;
2197 inline bool isPixelAligned(
const QRectF &rect)
2199 return QRectF(rect.toRect()) == rect;
2204
2205
2206void QRasterPaintEngine::drawImage(
const QRectF &r,
const QImage &img,
const QRectF &sr,
2207 Qt::ImageConversionFlags)
2210 qDebug() <<
" - QRasterPaintEngine::drawImage(), r=" << r <<
" sr=" << sr <<
" image=" << img.size() <<
"depth=" << img.depth();
2216 Q_D(QRasterPaintEngine);
2217 QRasterPaintEngineState *s = state();
2219 int sr_l = qFloor(sr.left());
2220 int sr_r = qCeil(sr.right()) - 1;
2221 int sr_t = qFloor(sr.top());
2222 int sr_b = qCeil(sr.bottom()) - 1;
2224 if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2227 QTransform old = s->matrix;
2230 QRgb color = img.pixel(sr_l, sr_t);
2231 if (img.pixelFormat().premultiplied() == QPixelFormat::Premultiplied) {
2233 d->solid_color_filler.solidColor = multiplyAlpha256(QRgba64::fromArgb32(color), s->intOpacity);
2235 d->solid_color_filler.solidColor = qPremultiply(combineAlpha256(QRgba64::fromArgb32(color), s->intOpacity));
2238 if (d->solid_color_filler.solidColor.alphaF() <= 0.0f && s->composition_mode == QPainter::CompositionMode_SourceOver)
2241 d->solid_color_filler.clip = d->clip();
2242 d->solid_color_filler.adjustSpanMethods();
2243 fillRect(r, &d->solid_color_filler);
2249 bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2251 const QClipData *clip = d->clip();
2253 if (s->matrix.type() == QTransform::TxRotate
2255 && (!clip || clip->hasRectClip)
2256 && s->intOpacity == 256
2257 && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2258 || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
2260 RotationType rotationType = qRotationType(s->matrix);
2261 Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats);
2262 const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
2264 if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2265 QRectF transformedTargetRect = s->matrix.mapRect(r);
2267 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, transformedTargetRect.topRight(), sr)) {
2268 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2269 if (clippedTransformedTargetRect.isNull())
2272 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2274 QRect clippedSourceRect
2275 = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2276 clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2278 clippedSourceRect = clippedSourceRect.intersected(img.rect());
2280 const qsizetype dbpl = d->rasterBuffer->bytesPerLine();
2281 const qsizetype sbpl = img.bytesPerLine();
2283 uchar *dst = d->rasterBuffer->buffer();
2284 uint bpp = img.depth() >> 3;
2286 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2287 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2289 uint cw = clippedSourceRect.width();
2290 uint ch = clippedSourceRect.height();
2292 qMemRotateFunctions[plBpp][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2299 if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2301 QRectF targetBounds = s->matrix.mapRect(r);
2302 bool exceedsPrecision = r.width() > 0x7fff
2303 || r.height() > 0x7fff
2304 || targetBounds.left() < -0x7fff
2305 || targetBounds.top() < -0x7fff
2306 || targetBounds.right() > 0x7fff
2307 || targetBounds.bottom() > 0x7fff
2308 || targetBounds.width() > 0x7fff
2309 || targetBounds.height() > 0x7fff
2310 || s->matrix.m11() >= 512
2311 || s->matrix.m22() >= 512;
2312 if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2313 if (s->matrix.type() > QTransform::TxScale) {
2314 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2317 if (func && (!clip || clip->hasRectClip) && !s->flags.antialiased && targetBounds.width() >= 16 && targetBounds.height() >= 16) {
2318 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2319 img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2320 s->matrix, s->intOpacity);
2325 bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
2326 bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
2327 if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
2328 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2330 QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
2332 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2334 }
else if (clip->hasRectClip) {
2335 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2340 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2341 if (func && (!clip || clip->hasRectClip)) {
2342 QRectF tr = qt_mapRect_non_normalizing(r, s->matrix);
2343 if (!s->flags.antialiased) {
2344 tr.setX(qRound(tr.x()));
2345 tr.setY(qRound(tr.y()));
2346 tr.setWidth(qRound(tr.width()));
2347 tr.setHeight(qRound(tr.height()));
2349 func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2350 img.bits(), img.bytesPerLine(), img.height(),
2352 !clip ? d->deviceRect : clip->clipRect,
2359 QTransform copy = s->matrix;
2360 copy.translate(r.x(), r.y());
2362 copy.scale(r.width() / sr.width(), r.height() / sr.height());
2363 copy.translate(-sr.x(), -sr.y());
2365 d->image_filler_xform.clip = clip;
2366 d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2367 if (!d->image_filler_xform.blend)
2369 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2371 if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2372 QRectF rr = s->matrix.mapRect(r);
2374 const int x1 = qRound(rr.x());
2375 const int y1 = qRound(rr.y());
2376 const int x2 = qRound(rr.right());
2377 const int y2 = qRound(rr.bottom());
2379 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2384 ensureRasterState();
2385 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2386 d->initializeRasterizer(&d->image_filler_xform);
2387 d->rasterizer->setAntialiased(s->flags.antialiased);
2389 const QRectF &rect = r.normalized();
2390 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2391 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2393 if (s->flags.tx_noshear)
2394 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2396 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2402 QTransform m = s->matrix;
2403 s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2404 m.m21(), m.m22(), m.m23(),
2405 m.m31(), m.m32(), m.m33());
2406 fillPath(path, &d->image_filler_xform);
2409 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2410 if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, sr)) {
2412 d->blitImage(pt, img, d->deviceRect, sr.toRect());
2414 }
else if (clip->hasRectClip) {
2415 d->blitImage(pt, img, clip->clipRect, sr.toRect());
2418 }
else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2419 SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2422 d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2424 }
else if (clip->hasRectClip) {
2425 d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2431 d->image_filler.clip = clip;
2432 d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2433 if (!d->image_filler.blend)
2435 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2436 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2439 rr.translate(s->matrix.dx(), s->matrix.dy());
2441 const int x1 = qRound(rr.x());
2442 const int y1 = qRound(rr.y());
2443 const int x2 = qRound(rr.right());
2444 const int y2 = qRound(rr.bottom());
2446 fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2451
2452
2453void QRasterPaintEngine::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sr)
2456 qDebug() <<
" - QRasterPaintEngine::drawTiledPixmap(), r=" << r <<
"pixmap=" << pixmap.size();
2458 Q_D(QRasterPaintEngine);
2459 QRasterPaintEngineState *s = state();
2464 QPlatformPixmap *pd = pixmap.handle();
2465 if (pd->classId() == QPlatformPixmap::RasterClass) {
2466 image =
static_cast<QRasterPlatformPixmap *>(pd)->image;
2468 image = pixmap.toImage();
2471 if (image.depth() == 1)
2472 image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2474 const qreal pixmapDevicePixelRatio = pixmap.devicePixelRatio();
2475 if (s->matrix.type() > QTransform::TxTranslate || pixmapDevicePixelRatio > qreal(1.0)) {
2476 QTransform copy = s->matrix;
2477 copy.translate(r.x(), r.y());
2478 copy.translate(-sr.x(), -sr.y());
2479 const qreal inverseDpr = qreal(1.0) / pixmapDevicePixelRatio;
2480 copy.scale(inverseDpr, inverseDpr);
2481 d->image_filler_xform.clip = d->clip();
2482 d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2483 if (!d->image_filler_xform.blend)
2485 d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2488 ensureRasterState();
2489 if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2490 d->initializeRasterizer(&d->image_filler_xform);
2491 d->rasterizer->setAntialiased(s->flags.antialiased);
2493 const QRectF &rect = r.normalized();
2494 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2495 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2496 if (s->flags.tx_noshear)
2497 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2499 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2505 fillPath(path, &d->image_filler_xform);
2507 d->image_filler.clip = d->clip();
2509 d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2510 if (!d->image_filler.blend)
2512 d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2513 d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2516 rr.translate(s->matrix.dx(), s->matrix.dy());
2517 fillRect_normalized(rr.normalized().toRect(), &d->image_filler, d);
2525 return (s[x>>3] << (x&7)) & 0x80;
2529
2530
2531QRasterBuffer *QRasterPaintEngine::rasterBuffer()
2533 Q_D(QRasterPaintEngine);
2534 return d->rasterBuffer.data();
2538
2539
2540void QRasterPaintEngine::alphaPenBlt(
const void* src,
int bpl,
int depth,
int rx,
int ry,
int w,
int h,
bool useGammaCorrection)
2542 Q_D(QRasterPaintEngine);
2543 QRasterPaintEngineState *s = state();
2545 if (!s->penData.blend)
2548 QRasterBuffer *rb = d->rasterBuffer.data();
2549 if (rb->colorSpace.transferFunction() == QColorSpace::TransferFunction::Linear)
2550 useGammaCorrection =
false;
2552 const QRect rect(rx, ry, w, h);
2553 const QClipData *clip = d->clip();
2554 bool unclipped =
false;
2557 const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2558 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2560 if (clip->hasRectClip) {
2561 unclipped = rx > clip->xmin
2562 && rx + w < clip->xmax
2564 && ry + h < clip->ymax;
2571 const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2572 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2577 const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2578 && rect.top() >= 0 && rect.bottom() < rb->height();
2580 unclipped = contains && d->isUnclipped_normalized(rect);
2583 ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2584 const uchar * scanline =
static_cast<
const uchar *>(src);
2586 if (s->flags.fast_text) {
2589 if (s->penData.bitmapBlit) {
2590 s->penData.bitmapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2591 scanline, w, h, bpl);
2594 }
else if (depth == 8) {
2595 if (s->penData.alphamapBlit) {
2596 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2597 scanline, w, h, bpl,
nullptr, useGammaCorrection);
2600 }
else if (depth == 32) {
2602 if (s->penData.alphaRGBBlit) {
2603 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2604 (
const uint *) scanline, w, h, bpl / 4,
nullptr, useGammaCorrection);
2608 }
else if ((depth == 8 && s->penData.alphamapBlit) || (depth == 32 && s->penData.alphaRGBBlit)) {
2611 int nx = qMax(0, rx);
2612 int ny = qMax(0, ry);
2615 int xdiff = nx - rx;
2616 int ydiff = ny - ry;
2617 scanline += ydiff * bpl;
2618 scanline += xdiff * (depth == 32 ? 4 : 1);
2623 if (nx + w > d->rasterBuffer->width())
2624 w = d->rasterBuffer->width() - nx;
2625 if (ny + h > d->rasterBuffer->height())
2626 h = d->rasterBuffer->height() - ny;
2632 s->penData.alphamapBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2633 scanline, w, h, bpl, clip, useGammaCorrection);
2634 else if (depth == 32)
2635 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solidColor.rgba64(),
2636 (
const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
2650 scanline += bpl * y0;
2654 w = qMin(w, rb->width() - qMax(0, rx));
2655 h = qMin(h, rb->height() - qMax(0, ry));
2657 if (w <= 0 || h <= 0)
2660 const int NSPANS = 512;
2661 QT_FT_Span spans[NSPANS];
2664 const int x1 = x0 + w;
2665 const int y1 = y0 + h;
2668 for (
int y = y0; y < y1; ++y) {
2669 for (
int x = x0; x < x1; ) {
2670 if (!monoVal(scanline, x)) {
2675 if (current == NSPANS) {
2676 blend(current, spans, &s->penData);
2679 spans[current].x = x + rx;
2680 spans[current].y = y + ry;
2681 spans[current].coverage = 255;
2685 while (x < x1 && monoVal(scanline, x)) {
2689 spans[current].len = len;
2694 }
else if (depth == 8) {
2695 for (
int y = y0; y < y1; ++y) {
2696 for (
int x = x0; x < x1; ) {
2698 if (scanline[x] == 0) {
2703 if (current == NSPANS) {
2704 blend(current, spans, &s->penData);
2707 int coverage = scanline[x];
2708 spans[current].x = x + rx;
2709 spans[current].y = y + ry;
2710 spans[current].coverage = coverage;
2715 while (x < x1 && scanline[x] == coverage) {
2719 spans[current].len = len;
2725 const uint *sl = (
const uint *) scanline;
2726 for (
int y = y0; y < y1; ++y) {
2727 for (
int x = x0; x < x1; ) {
2729 if ((sl[x] & 0x00ffffff) == 0) {
2734 if (current == NSPANS) {
2735 blend(current, spans, &s->penData);
2738 uint rgbCoverage = sl[x];
2739 int coverage = qGreen(rgbCoverage);
2740 spans[current].x = x + rx;
2741 spans[current].y = y + ry;
2742 spans[current].coverage = coverage;
2747 while (x < x1 && sl[x] == rgbCoverage) {
2751 spans[current].len = len;
2754 sl += bpl /
sizeof(uint);
2761 blend(current, spans, &s->penData);
2765
2766
2767bool QRasterPaintEngine::drawCachedGlyphs(
int numGlyphs,
const glyph_t *glyphs,
2768 const QFixedPoint *positions, QFontEngine *fontEngine)
2770 Q_D(QRasterPaintEngine);
2771 QRasterPaintEngineState *s = state();
2773 bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
2774 && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
2776 if (fontEngine->hasInternalCaching()) {
2777 QFontEngine::GlyphFormat neededFormat =
2778 painter()->device()->devType() == QInternal::Widget
2779 ? QFontEngine::Format_None
2780 : QFontEngine::Format_A8;
2782 if (d_func()->mono_surface)
2783 neededFormat = QFontEngine::Format_Mono;
2785 for (
int i = 0; i < numGlyphs; i++) {
2786 QFixedPoint spp = fontEngine->subPixelPositionFor(positions[i]);
2787 if (!verticalSubPixelPositions)
2790 const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
2796 switch (alphaMap->format) {
2797 case QFontEngine::Format_Mono:
2799 bytesPerLine = ((alphaMap->width + 31) & ~31) >> 3;
2801 case QFontEngine::Format_A8:
2803 bytesPerLine = (alphaMap->width + 3) & ~3;
2805 case QFontEngine::Format_A32:
2807 bytesPerLine = alphaMap->width * 4;
2813 QFixed y = verticalSubPixelPositions
2814 ? qFloor(positions[i].y)
2815 : qRound(positions[i].y);
2817 alphaPenBlt(alphaMap->data, bytesPerLine, depth,
2818 qFloor(positions[i].x) + alphaMap->x,
2819 qFloor(y) - alphaMap->y,
2820 alphaMap->width, alphaMap->height,
2821 fontEngine->expectsGammaCorrectedBlending(QFontEngine::GlyphFormat(alphaMap->format)));
2825 QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
2827 QImageTextureGlyphCache *cache =
2828 static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(
nullptr, glyphFormat, s->matrix, s->penData.solidColor));
2830 cache =
new QImageTextureGlyphCache(glyphFormat, s->matrix, s->penData.solidColor);
2831 fontEngine->setGlyphCache(
nullptr, cache);
2834 cache->populate(fontEngine, numGlyphs, glyphs, positions, s->renderHints);
2835 cache->fillInPendingGlyphs();
2837 const QImage &image = cache->image();
2838 qsizetype bpl = image.bytesPerLine();
2840 int depth = image.depth();
2845 else if (depth == 1)
2848 int margin = fontEngine->glyphMargin(glyphFormat);
2849 const uchar *bits = image.bits();
2850 for (
int i=0; i<numGlyphs; ++i) {
2851 QFixedPoint subPixelPosition = fontEngine->subPixelPositionFor(positions[i]);
2852 if (!verticalSubPixelPositions)
2853 subPixelPosition.y = 0;
2855 QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2856 const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2860 int x = qFloor(positions[i].x) + c.baseLineX - margin;
2861 int y = (verticalSubPixelPositions
2862 ? qFloor(positions[i].y)
2863 : qRound(positions[i].y));
2864 y -= c.baseLineY + margin;
2874 const uchar *glyphBits = bits + ((c.x << leftShift) >> rightShift) + c.y * bpl;
2876 if (glyphFormat == QFontEngine::Format_ARGB) {
2880 QTransform originalTransform = s->matrix;
2881 s->matrix = QTransform();
2882 drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format()));
2883 s->matrix = originalTransform;
2885 alphaPenBlt(glyphBits,
2892 fontEngine->expectsGammaCorrectedBlending(glyphFormat));
2901
2902
2903
2904
2910 const QRect &r1 = deviceRect;
2911 return (r.left() >= r1.left() && r.right() <= r1.right()
2912 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2918 if (cl->clipRect == deviceRect)
2922 const QRect &r1 = cl->clipRect;
2923 return (r.left() >= r1.left() && r.right() <= r1.right()
2924 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2926 return qt_region_strictContains(cl->clipRegion, r);
2933 Q_Q(
const QRasterPaintEngine);
2936 QRect r = rect.normalized();
2939 const QRect &r1 = deviceRect;
2940 return (r.left() >= r1.left() && r.right() <= r1.right()
2941 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2946 if (cl->hasRectClip && cl->clipRect == deviceRect)
2953 r.setX(r.x() - penWidth);
2954 r.setY(r.y() - penWidth);
2955 r.setWidth(r.width() + 2 * penWidth);
2956 r.setHeight(r.height() + 2 * penWidth);
2961 const QRect &r1 = cl->clipRect;
2962 return (r.left() >= r1.left() && r.right() <= r1.right()
2963 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2965 return qt_region_strictContains(cl->clipRegion, r);
2972 const QRectF norm = rect.normalized();
2973 if (norm.left() <= qreal(INT_MIN) || norm.top() <= qreal(INT_MIN)
2974 || norm.right() > qreal(INT_MAX) || norm.bottom() > qreal(INT_MAX)
2975 || norm.width() > qreal(INT_MAX) || norm.height() > qreal(INT_MAX))
2977 return isUnclipped(norm.toAlignedRect(), penWidth);
2982 const QSpanData *data)
const
2984 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2989 const QSpanData *data)
const
2991 return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2996 const QSpanData *data)
const
2998 Q_Q(
const QRasterPaintEngine);
3001 if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3004 return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3014 glyph_t *glyphs, QFixedPoint *positions,
int numGlyphs)
3016 QFixed clipLeft = QFixed::fromReal(clip.left() - 1);
3017 QFixed clipRight = QFixed::fromReal(clip.right() + 1);
3018 QFixed clipTop = QFixed::fromReal(clip.top() - 1);
3019 QFixed clipBottom = QFixed::fromReal(clip.bottom() + 1);
3022 while (first < numGlyphs) {
3023 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
3024 QFixed left = metrics.x + positions[first].x;
3025 QFixed top = metrics.y + positions[first].y;
3026 QFixed right = left + metrics.width;
3027 QFixed bottom = top + metrics.height;
3028 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3032 int last = numGlyphs - 1;
3033 while (last > first) {
3034 glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
3035 QFixed left = metrics.x + positions[last].x;
3036 QFixed top = metrics.y + positions[last].y;
3037 QFixed right = left + metrics.width;
3038 QFixed bottom = top + metrics.height;
3039 if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
3043 return {first, last + 1};
3047
3048
3049void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3051 if (textItem->numGlyphs == 0)
3055 ensureRasterState();
3057 QTransform matrix = state()->matrix;
3059 QFontEngine *fontEngine = textItem->fontEngine();
3060 if (shouldDrawCachedGlyphs(fontEngine, matrix)) {
3061 drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3063 }
else if (matrix.type() < QTransform::TxProject) {
3065 QTransform invMat = matrix.inverted(&invertible);
3069 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3070 textItem->fontEngine(), textItem->glyphs,
3071 textItem->glyphPositions, textItem->numGlyphs);
3072 QStaticTextItem copy = *textItem;
3073 copy.glyphs += range.begin;
3074 copy.glyphPositions += range.begin;
3075 copy.numGlyphs = range.end - range.begin;
3076 QPaintEngineEx::drawStaticTextItem(©);
3078 QPaintEngineEx::drawStaticTextItem(textItem);
3083
3084
3085void QRasterPaintEngine::drawTextItem(
const QPointF &p,
const QTextItem &textItem)
3087 const QTextItemInt &ti =
static_cast<
const QTextItemInt &>(textItem);
3090 Q_D(QRasterPaintEngine);
3091 fprintf(stderr,
" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3092 p.x(), p.y(), QStringView(ti.chars, ti.num_chars).toLatin1().data(),
3093 d->glyphCacheFormat);
3096 if (ti.glyphs.numGlyphs == 0)
3099 ensureRasterState();
3101 QRasterPaintEngineState *s = state();
3102 QTransform matrix = s->matrix;
3104 if (shouldDrawCachedGlyphs(ti.fontEngine, matrix)) {
3105 QVarLengthArray<QFixedPoint> positions;
3106 QVarLengthArray<glyph_t> glyphs;
3108 matrix.translate(p.x(), p.y());
3109 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3111 drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3112 }
else if (matrix.type() < QTransform::TxProject
3113 && ti.fontEngine->supportsTransformation(matrix)) {
3115 QTransform invMat = matrix.inverted(&invertible);
3119 QVarLengthArray<QFixedPoint> positions;
3120 QVarLengthArray<glyph_t> glyphs;
3122 ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3123 ti.flags, glyphs, positions);
3124 const auto range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3125 ti.fontEngine, glyphs.data(), positions.data(),
3128 if (range.begin >= range.end)
3131 QStaticTextItem staticTextItem;
3132 staticTextItem.color = s->pen.color();
3133 staticTextItem.font = s->font;
3134 staticTextItem.setFontEngine(ti.fontEngine);
3135 staticTextItem.numGlyphs = range.end - range.begin;
3136 staticTextItem.glyphs = glyphs.data() + range.begin;
3137 staticTextItem.glyphPositions = positions.data() + range.begin;
3138 QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3140 QPaintEngineEx::drawTextItem(p, ti);
3145
3146
3147void QRasterPaintEngine::drawPoints(
const QPointF *points,
int pointCount)
3149 Q_D(QRasterPaintEngine);
3150 QRasterPaintEngineState *s = state();
3153 if (!s->penData.blend)
3156 if (!s->flags.fast_pen) {
3157 QPaintEngineEx::drawPoints(points, pointCount);
3161 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3162 stroker.drawPoints(points, pointCount);
3166void QRasterPaintEngine::drawPoints(
const QPoint *points,
int pointCount)
3168 Q_D(QRasterPaintEngine);
3169 QRasterPaintEngineState *s = state();
3172 if (!s->penData.blend)
3175 if (!s->flags.fast_pen) {
3176 QPaintEngineEx::drawPoints(points, pointCount);
3180 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3181 stroker.drawPoints(points, pointCount);
3185
3186
3187void QRasterPaintEngine::drawLines(
const QLine *lines,
int lineCount)
3190 qDebug() <<
" - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3192 Q_D(QRasterPaintEngine);
3193 QRasterPaintEngineState *s = state();
3196 if (!s->penData.blend)
3199 if (s->flags.fast_pen) {
3200 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3201 for (
int i=0; i<lineCount; ++i) {
3202 const QLine &l = lines[i];
3203 stroker.drawLine(l.p1(), l.p2());
3206 QPaintEngineEx::drawLines(lines, lineCount);
3216 Q_Q(QRasterPaintEngine);
3219 const QPen &pen = s->lastPen;
3220 const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3221 const QList<qreal> pattern = pen.dashPattern();
3223 qreal patternLength = 0;
3224 for (
int i = 0; i < pattern.size(); ++i)
3225 patternLength += pattern.at(i);
3227 if (patternLength <= 0)
3230 qreal length = line.length();
3231 Q_ASSERT(length > 0);
3232 if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
3233 rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
3237 while (length > 0) {
3238 const bool rasterize = *inDash;
3239 qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3242 if (dash >= length) {
3243 dash = line.length();
3244 *dashOffset += dash / width;
3248 *inDash = !(*inDash);
3249 if (++*dashIndex >= pattern.size())
3256 if (rasterize && dash > 0)
3257 rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3262
3263
3264void QRasterPaintEngine::drawLines(
const QLineF *lines,
int lineCount)
3267 qDebug() <<
" - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3269 Q_D(QRasterPaintEngine);
3270 QRasterPaintEngineState *s = state();
3273 if (!s->penData.blend)
3275 if (s->flags.fast_pen) {
3276 QCosmeticStroker stroker(s, d->deviceRect, d->deviceRectUnclipped);
3277 for (
int i=0; i<lineCount; ++i) {
3278 QLineF line = lines[i];
3279 stroker.drawLine(line.p1(), line.p2());
3282 QPaintEngineEx::drawLines(lines, lineCount);
3288
3289
3290void QRasterPaintEngine::drawEllipse(
const QRectF &rect)
3292 Q_D(QRasterPaintEngine);
3293 QRasterPaintEngineState *s = state();
3296 if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3297 || (qpen_style(s->lastPen) == Qt::NoPen))
3298 && !s->flags.antialiased
3299 && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3301 && s->matrix.type() <= QTransform::TxScale)
3304 const QRectF r = s->matrix.mapRect(rect);
3305 ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3306 ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3307 const QRect brect = QRect(
int(r.x()),
int(r.y()),
3311 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3312 &s->penData, &s->brushData);
3316 QPaintEngineEx::drawEllipse(rect);
3322
3323
3324void QRasterPaintEngine::setDC(HDC hdc) {
3325 Q_D(QRasterPaintEngine);
3330
3331
3332HDC QRasterPaintEngine::getDC()
const
3334 Q_D(
const QRasterPaintEngine);
3339
3340
3341void QRasterPaintEngine::releaseDC(HDC)
const
3348
3349
3350bool QRasterPaintEngine::requiresPretransformedGlyphPositions(QFontEngine *fontEngine,
const QTransform &m)
const
3353 if (shouldDrawCachedGlyphs(fontEngine, m))
3357 return QPaintEngineEx::requiresPretransformedGlyphPositions(fontEngine, m);
3361
3362
3363
3364bool QRasterPaintEngine::shouldDrawCachedGlyphs(QFontEngine *fontEngine,
const QTransform &m)
const
3367 if (m.type() >= QTransform::TxProject)
3375 if (!fontEngine->hasInternalCaching() && !fontEngine->supportsTransformation(m))
3378 if (fontEngine->supportsTransformation(m) && !fontEngine->isSmoothlyScalable)
3381 return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, m);
3385
3386
3387QPoint QRasterPaintEngine::coordinateOffset()
const
3389 return QPoint(0, 0);
3392void QRasterPaintEngine::drawBitmap(
const QPointF &pos,
const QImage &image, QSpanData *fg)
3397 Q_D(QRasterPaintEngine);
3399 Q_ASSERT(image.depth() == 1);
3401 const int spanCount = 512;
3402 QT_FT_Span spans[spanCount];
3406 int w = image.width();
3407 int h = image.height();
3408 int px = qRound(pos.x());
3409 int py = qRound(pos.y());
3410 int ymax = qMin(py + h, d->rasterBuffer->height());
3411 int ymin = qMax(py, 0);
3412 int xmax = qMin(px + w, d->rasterBuffer->width());
3413 int xmin = qMax(px, 0);
3415 int x_offset = xmin - px;
3417 QImage::Format format = image.format();
3418 for (
int y = ymin; y < ymax; ++y) {
3419 const uchar *src = image.scanLine(y - py);
3420 if (format == QImage::Format_MonoLSB) {
3421 for (
int x = 0; x < xmax - xmin; ++x) {
3422 int src_x = x + x_offset;
3423 uchar pixel = src[src_x >> 3];
3428 if (pixel & (0x1 << (src_x & 7))) {
3429 spans[n].x = xmin + x;
3431 spans[n].coverage = 255;
3433 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3437 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3440 if (n == spanCount) {
3441 fg->blend(n, spans, fg);
3447 for (
int x = 0; x < xmax - xmin; ++x) {
3448 int src_x = x + x_offset;
3449 uchar pixel = src[src_x >> 3];
3454 if (pixel & (0x80 >> (x & 7))) {
3455 spans[n].x = xmin + x;
3457 spans[n].coverage = 255;
3459 while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3463 spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3466 if (n == spanCount) {
3467 fg->blend(n, spans, fg);
3475 fg->blend(n, spans, fg);
3481
3482
3483
3484
3485
3486
3489
3490
3491
3492QRasterPaintEngine::ClipType QRasterPaintEngine::clipType()
const
3494 Q_D(
const QRasterPaintEngine);
3496 const QClipData *clip = d->clip();
3497 if (!clip || clip->hasRectClip)
3504
3505
3506
3507QRectF QRasterPaintEngine::clipBoundingRect()
const
3509 Q_D(
const QRasterPaintEngine);
3511 const QClipData *clip = d->clip();
3514 return d->deviceRect;
3516 if (clip->hasRectClip)
3517 return clip->clipRect;
3519 return QRectF(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3524 Q_Q(QRasterPaintEngine);
3527 rasterizer->setAntialiased(s->flags.antialiased);
3529 QRect clipRect(deviceRect);
3537 clipRect = clipRect.intersected(r);
3538 blend = data->blend;
3540 blend = data->unclipped_blend;
3543 rasterizer->setClipRect(clipRect);
3544 rasterizer->initialize(blend, data);
3548 ProcessSpans callback,
3551 if (!callback || !outline)
3554 Q_Q(QRasterPaintEngine);
3558 initializeRasterizer(spanData);
3560 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3564 rasterizer->rasterize(outline, fillRule);
3568 rasterize(outline, callback, (
void *)spanData, rasterBuffer);
3577 return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3581 ProcessSpans callback,
3584 if (!callback || !outline)
3587 Q_Q(QRasterPaintEngine);
3591 rasterizer->setAntialiased(s->flags.antialiased);
3592 rasterizer->setClipRect(deviceRect);
3593 rasterizer->initialize(callback, userData);
3595 const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3599 rasterizer->rasterize(outline, fillRule);
3607 unsigned int rasterPoolSize = MINIMUM_POOL_SIZE;
3608 Q_DECL_UNINITIALIZED uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3609 uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3610 uchar *rasterPoolOnHeap =
nullptr;
3612 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3614 void *data = userData;
3616 QT_FT_BBox clip_box = { deviceRect.x(),
3618 deviceRect.x() + deviceRect.width(),
3619 deviceRect.y() + deviceRect.height() };
3621 QT_FT_Raster_Params rasterParams;
3622 rasterParams.target =
nullptr;
3623 rasterParams.source = outline;
3624 rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3625 rasterParams.gray_spans =
nullptr;
3626 rasterParams.black_spans =
nullptr;
3627 rasterParams.bit_test =
nullptr;
3628 rasterParams.bit_set =
nullptr;
3629 rasterParams.user = data;
3630 rasterParams.clip_box = clip_box;
3635 int rendered_spans = 0;
3639 rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3640 rasterParams.gray_spans = callback;
3641 rasterParams.skip_spans = rendered_spans;
3642 error = QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_render(*grayRaster.data(), &rasterParams);
3646 rasterPoolSize *= 2;
3647 if (rasterPoolSize > 1024 * 1024) {
3648 qWarning(
"QPainter: Rasterization of primitive failed");
3652 rendered_spans += QT_MANGLE_NAMESPACE(q_gray_rendered_spans)(*grayRaster.data());
3654 free(rasterPoolOnHeap);
3655 rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3657 Q_CHECK_PTR(rasterPoolOnHeap);
3659 rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3661 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_done(*grayRaster.data());
3662 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_new(grayRaster.data());
3663 QT_MANGLE_NAMESPACE(qt_ft_grays_raster).raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3669 free(rasterPoolOnHeap);
3674 Q_Q(QRasterPaintEngine);
3677 if (!s->clipEnabled)
3681 replayClipOperations();
3686 Q_Q(QRasterPaintEngine);
3689 s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3690 && s->matrix.type() <= QTransform::TxShear;
3695 Q_Q(
const QRasterPaintEngine);
3698 return s->flags.fast_images
3699 && (mode == QPainter::CompositionMode_SourceOver
3700 || (mode == QPainter::CompositionMode_Source
3701 && !image.hasAlphaChannel()));
3706 Q_Q(
const QRasterPaintEngine);
3708 if (!(mode == QPainter::CompositionMode_Source
3709 || (mode == QPainter::CompositionMode_SourceOver
3710 && !image.hasAlphaChannel())))
3714 Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
3716 if (s->intOpacity != 256
3717 || image.depth() < 8
3718 || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
3719 && (!isPixelAligned(pt) || !isPixelAligned(sr))))
3722 QImage::Format dFormat = rasterBuffer->format;
3723 QImage::Format sFormat = image.format();
3725 if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
3726 dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
3727 return (dFormat == sFormat);
3732 Q_ASSERT(image.depth() == 1);
3734 const QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3735 QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3736 if (sourceImage.isNull() || dest.isNull())
3739 QRgb fg = qPremultiply(color.rgba());
3742 int height = sourceImage.height();
3743 int width = sourceImage.width();
3744 for (
int y=0; y<height; ++y) {
3745 const uchar *source = sourceImage.constScanLine(y);
3746 QRgb *target =
reinterpret_cast<QRgb *>(dest.scanLine(y));
3747 for (
int x=0; x < width; ++x)
3748 target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3759 compositionMode = QPainter::CompositionMode_SourceOver;
3767 m_buffer = (uchar *)image->bits();
3770 bytes_per_pixel = image->depth()/8;
3771 bytes_per_line = image->bytesPerLine();
3773 format = image->format();
3774 colorSpace = image->colorSpace();
3775 if (image->depth() == 1 && image->colorTable().size() == 2) {
3777 const QList<QRgb> colorTable = image->colorTable();
3778 destColor0 = qPremultiply(colorTable[0]);
3779 destColor1 = qPremultiply(colorTable[1]);
3788 m_clipLines =
nullptr;
3813 m_clipLines = (ClipLine *)calloc(clipSpanHeight,
sizeof(ClipLine));
3815 Q_CHECK_PTR(m_clipLines);
3817 allocated = clipSpanHeight;
3820 if (hasRegionClip) {
3821 const auto rects = clipRegion.begin();
3822 const int numRects = clipRegion.rectCount();
3823 const int maxSpans = (ymax - ymin) * numRects;
3824 allocated = qMax(allocated, maxSpans);
3825 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3826 Q_CHECK_PTR(m_spans);
3829 int firstInBand = 0;
3830 while (firstInBand < numRects) {
3831 const int currMinY = rects[firstInBand].y();
3832 const int currMaxY = currMinY + rects[firstInBand].height();
3834 while (y < currMinY) {
3835 m_clipLines[y].spans =
nullptr;
3836 m_clipLines[y].count = 0;
3840 int lastInBand = firstInBand;
3841 while (lastInBand + 1 < numRects && rects[lastInBand+1].top() == y)
3844 while (y < currMaxY) {
3846 m_clipLines[y].spans = m_spans + count;
3847 m_clipLines[y].count = lastInBand - firstInBand + 1;
3849 for (
int r = firstInBand; r <= lastInBand; ++r) {
3850 const QRect &currRect = rects[r];
3851 QT_FT_Span *span = m_spans + count;
3852 span->x = currRect.x();
3853 span->len = currRect.width();
3855 span->coverage = 255;
3861 firstInBand = lastInBand + 1;
3864 Q_ASSERT(count <= allocated);
3866 while (y < clipSpanHeight) {
3867 m_clipLines[y].spans =
nullptr;
3868 m_clipLines[y].count = 0;
3875 m_spans = (QT_FT_Span *)malloc(allocated *
sizeof(QT_FT_Span));
3876 Q_CHECK_PTR(m_spans);
3881 m_clipLines[y].spans =
nullptr;
3882 m_clipLines[y].count = 0;
3886 const int len = clipRect.width();
3888 QT_FT_Span *span = m_spans + count;
3892 span->coverage = 255;
3895 m_clipLines[y].spans = span;
3896 m_clipLines[y].count = 1;
3900 while (y < clipSpanHeight) {
3901 m_clipLines[y].spans =
nullptr;
3902 m_clipLines[y].count = 0;
3913 m_clipLines =
nullptr;
3928 ymin = m_spans[0].y;
3929 ymax = m_spans[count-1].y + 1;
3933 const int firstLeft = m_spans[0].x;
3934 const int firstRight = m_spans[0].x + m_spans[0].len;
3937 for (
int i = 0; i <
count; ++i) {
3938 QT_FT_Span_& span = m_spans[i];
3941 if (span.y != y + 1 && y != -1)
3944 m_clipLines[y].spans = &span;
3945 m_clipLines[y]
.count = 1;
3949 const int spanLeft = span.x;
3950 const int spanRight = spanLeft + span.len;
3952 if (spanLeft <
xmin)
3955 if (spanRight >
xmax)
3958 if (spanLeft != firstLeft || spanRight != firstRight)
3964 clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3969
3970
3973 if (hasRectClip && rect == clipRect)
3982 xmax = rect.x() + rect.width();
3995
3996
3999 if (region.rectCount() == 1) {
4000 setClipRect(region.boundingRect());
4006 clipRegion = region;
4009 const QRect rect = region.boundingRect();
4011 xmax = rect.x() + rect.width();
4013 ymax = rect.y() + rect.height();
4024
4025
4026
4028 const QT_FT_Span *spans,
const QT_FT_Span *end,
4029 QT_FT_Span **outSpans,
int available)
4033 QT_FT_Span *out = *outSpans;
4035 const QT_FT_Span *clipSpans = clip->m_spans + *currentClip;
4036 const QT_FT_Span *clipEnd = clip->m_spans + clip
->count;
4038 while (available && spans < end ) {
4039 if (clipSpans >= clipEnd) {
4043 if (clipSpans->y > spans->y) {
4047 if (spans->y != clipSpans->y) {
4048 if (spans->y < clip
->count && clip->m_clipLines[spans->y].spans)
4049 clipSpans = clip->m_clipLines[spans->y].spans;
4054 Q_ASSERT(spans->y == clipSpans->y);
4057 int sx2 = sx1 + spans->len;
4058 int cx1 = clipSpans->x;
4059 int cx2 = cx1 + clipSpans->len;
4061 if (cx1 < sx1 && cx2 < sx1) {
4064 }
else if (sx1 < cx1 && sx2 < cx1) {
4068 int x = qMax(sx1, cx1);
4069 int len = qMin(sx2, cx2) - x;
4071 out->x = qMax(sx1, cx1);
4072 out->len = qMin(sx2, cx2) - out->x;
4074 out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4086 *currentClip = clipSpans - clip->m_spans;
4093 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4095 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4097 const int NSPANS = 512;
4098 Q_DECL_UNINITIALIZED QT_FT_Span cspans[NSPANS];
4099 int currentClip = 0;
4100 const QT_FT_Span *end = spans + spanCount;
4101 while (spans < end) {
4102 QT_FT_Span *clipped = cspans;
4103 spans = qt_intersect_spans(fillData->clip, ¤tClip, spans, end, &clipped, NSPANS);
4107 if (clipped - cspans)
4108 fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4113
4114
4115
4116
4120 const int minx = clip.left();
4121 const int miny = clip.top();
4122 const int maxx = clip.right();
4123 const int maxy = clip.bottom();
4125 QT_FT_Span *end = spans + numSpans;
4126 while (spans < end) {
4127 if (spans->y >= miny)
4132 QT_FT_Span *s = spans;
4136 if (s->x > maxx || s->x + s->len <= minx) {
4142 s->len = qMin(s->len - (minx - s->x), maxx - minx + 1);
4145 s->len = qMin(s->len, (maxx - s->x + 1));
4157 QSpanData *fillData =
reinterpret_cast<QSpanData *>(userData);
4158 Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4160 Q_ASSERT(fillData->clip);
4161 Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4163 QT_FT_Span *s =
const_cast<QT_FT_Span *>(spans);
4165 count = qt_intersect_spans(s, count,
4166 fillData->clip->clipRect);
4168 fillData->unclipped_blend(count, s, fillData);
4171static void qt_span_clip(
int count,
const QT_FT_Span *spans,
void *userData)
4180 switch (clipData->operation) {
4182 case Qt::IntersectClip:
4187 int currentClip = 0;
4188 const QT_FT_Span *end = spans + count;
4189 while (spans < end) {
4190 QT_FT_Span *newspans = newClip->m_spans + newClip
->count;
4191 spans = qt_intersect_spans(clipData->oldClip, ¤tClip, spans, end,
4192 &newspans, newClip->allocated - newClip->count);
4193 newClip
->count = newspans - newClip->m_spans;
4195 newClip->m_spans = q_check_ptr((QT_FT_Span *)realloc(newClip->m_spans, newClip->allocated * 2 *
sizeof(QT_FT_Span)));
4202 case Qt::ReplaceClip:
4203 clipData
->newClip->appendSpans(spans, count);
4215 inline CacheInfo(QGradientStops s,
int op, QGradient::InterpolationMode mode) :
4227 quint64 hash_val = 0;
4229 const QGradientStops stops = gradient.stops();
4230 for (
int i = 0; i < stops.size() && i <= 2; i++)
4231 hash_val += stops[i].second.rgba64();
4233 QMutexLocker lock(&mutex);
4234 QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4236 if (it == cache.constEnd())
4237 return addCacheElement(hash_val, gradient, opacity);
4240 const auto &cache_info = it.value();
4241 if (cache_info->stops == stops && cache_info->opacity == opacity && cache_info->interpolationMode == gradient.interpolationMode())
4244 }
while (it != cache.constEnd() && it.key() == hash_val);
4246 return addCacheElement(hash_val, gradient, opacity);
4254 QRgba64 *colorTable,
4255 int size,
int opacity)
const;
4257 if (cache.size() == maxCacheSize()) {
4259 cache.erase(std::next(cache.begin(), QRandomGenerator::global()->bounded(maxCacheSize())));
4261 auto cache_entry =
std::make_shared<
CacheInfo>(gradient.stops(), opacity, gradient.interpolationMode());
4262 generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
4263 for (
int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
4264 cache_entry->buffer32[i] = cache_entry->buffer64[i].toArgb32();
4265 return cache.insert(hash_val, std::move(cache_entry)).value();
4274 const QGradientStops stops = gradient.stops();
4275 int stopCount = stops.size();
4276 Q_ASSERT(stopCount > 0);
4278 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4280 if (stopCount == 2) {
4281 QRgba64 first_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4282 QRgba64 second_color = combineAlpha256(stops[1].second.rgba64(), opacity);
4284 qreal first_stop = stops[0].first;
4285 qreal second_stop = stops[1].first;
4287 if (second_stop < first_stop) {
4288 quint64 tmp = first_color;
4289 first_color = second_color;
4291 qSwap(first_stop, second_stop);
4294 if (colorInterpolation) {
4295 first_color = qPremultiply(first_color);
4296 second_color = qPremultiply(second_color);
4299 int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4300 int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4302 uint red_first = uint(first_color.red()) << 16;
4303 uint green_first = uint(first_color.green()) << 16;
4304 uint blue_first = uint(first_color.blue()) << 16;
4305 uint alpha_first = uint(first_color.alpha()) << 16;
4307 uint red_second = uint(second_color.red()) << 16;
4308 uint green_second = uint(second_color.green()) << 16;
4309 uint blue_second = uint(second_color.blue()) << 16;
4310 uint alpha_second = uint(second_color.alpha()) << 16;
4313 for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4314 if (colorInterpolation)
4315 colorTable[i] = first_color;
4317 colorTable[i] = qPremultiply(first_color);
4320 if (i < second_index) {
4321 qreal reciprocal = qreal(1) / (second_index - first_index);
4323 int red_delta = qRound((qreal(red_second) - red_first) * reciprocal);
4324 int green_delta = qRound((qreal(green_second) - green_first) * reciprocal);
4325 int blue_delta = qRound((qreal(blue_second) - blue_first) * reciprocal);
4326 int alpha_delta = qRound((qreal(alpha_second) - alpha_first) * reciprocal);
4329 red_first += 1 << 15;
4330 green_first += 1 << 15;
4331 blue_first += 1 << 15;
4332 alpha_first += 1 << 15;
4334 for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4335 red_first += red_delta;
4336 green_first += green_delta;
4337 blue_first += blue_delta;
4338 alpha_first += alpha_delta;
4340 const QRgba64 color = qRgba64(red_first >> 16, green_first >> 16, blue_first >> 16, alpha_first >> 16);
4342 if (colorInterpolation)
4343 colorTable[i] = color;
4345 colorTable[i] = qPremultiply(color);
4349 for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4350 if (colorInterpolation)
4351 colorTable[i] = second_color;
4353 colorTable[i] = qPremultiply(second_color);
4359 QRgba64 current_color = combineAlpha256(stops[0].second.rgba64(), opacity);
4360 if (stopCount == 1) {
4361 current_color = qPremultiply(current_color);
4362 for (
int i = 0; i < size; ++i)
4363 colorTable[i] = current_color;
4368 qreal begin_pos = stops[0].first;
4369 qreal end_pos = stops[stopCount-1].first;
4374 qreal incr = 1 / qreal(size);
4375 qreal dpos = 1.5 * incr;
4378 colorTable[pos++] = qPremultiply(current_color);
4379 while (dpos <= begin_pos) {
4380 colorTable[pos] = colorTable[pos - 1];
4385 int current_stop = 0;
4390 if (dpos < end_pos) {
4392 while (dpos > stops[current_stop+1].first)
4395 if (current_stop != 0)
4396 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4397 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4399 if (colorInterpolation) {
4400 current_color = qPremultiply(current_color);
4401 next_color = qPremultiply(next_color);
4404 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4405 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4406 t = (dpos - stops[current_stop].first) * c;
4410 Q_ASSERT(current_stop < stopCount);
4412 int dist = qRound(t);
4413 int idist = 256 - dist;
4415 if (colorInterpolation)
4416 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
4418 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
4423 if (dpos >= end_pos)
4429 while (dpos > stops[current_stop+skip+1].first)
4433 current_stop += skip;
4435 current_color = next_color;
4437 current_color = combineAlpha256(stops[current_stop].second.rgba64(), opacity);
4438 next_color = combineAlpha256(stops[current_stop+1].second.rgba64(), opacity);
4440 if (colorInterpolation) {
4442 current_color = qPremultiply(current_color);
4443 next_color = qPremultiply(next_color);
4446 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4447 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4448 t = (dpos - stops[current_stop].first) * c;
4455 current_color = qPremultiply(combineAlpha256(stops[stopCount - 1].second.rgba64(), opacity));
4456 while (pos < size - 1) {
4457 colorTable[pos] = current_color;
4462 colorTable[size - 1] = current_color;
4468void QSpanData::init(QRasterBuffer *rb,
const QRasterPaintEngine *pe)
4474 m11 = m22 = m33 = 1.;
4475 m12 = m13 = m21 = m23 = dx = dy = 0.0;
4476 clip = pe ? pe->d_func()->clip() :
nullptr;
4479Q_GUI_EXPORT
extern QImage qt_imageForBrush(
int brushStyle,
bool invert);
4481void QSpanData::setup(
const QBrush &brush,
int alpha, QPainter::CompositionMode compositionMode,
4484 Qt::BrushStyle brushStyle = qbrush_style(brush);
4485 cachedGradient.reset();
4486 switch (brushStyle) {
4487 case Qt::SolidPattern: {
4489 QColor c = qbrush_color(brush);
4490 solidColor = qPremultiplyWithExtraAlpha(c, alpha);
4491 if (solidColor.alphaF() <= 0.0f && compositionMode == QPainter::CompositionMode_SourceOver)
4496 case Qt::LinearGradientPattern:
4498 type = LinearGradient;
4499 const QLinearGradient *g =
static_cast<
const QLinearGradient *>(brush.gradient());
4500 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4502 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4503 gradient.colorTable32 = cacheInfo->buffer32;
4504#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4505 gradient.colorTable64 = cacheInfo->buffer64;
4507 cachedGradient = std::move(cacheInfo);
4509 gradient.spread = g->spread();
4511 QLinearGradientData &linearData = gradient.linear;
4513 linearData.origin.x = g->start().x();
4514 linearData.origin.y = g->start().y();
4515 linearData.end.x = g->finalStop().x();
4516 linearData.end.y = g->finalStop().y();
4520 case Qt::RadialGradientPattern:
4522 type = RadialGradient;
4523 const QRadialGradient *g =
static_cast<
const QRadialGradient *>(brush.gradient());
4524 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4526 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4527 gradient.colorTable32 = cacheInfo->buffer32;
4528#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4529 gradient.colorTable64 = cacheInfo->buffer64;
4531 cachedGradient = std::move(cacheInfo);
4533 gradient.spread = g->spread();
4535 QRadialGradientData &radialData = gradient.radial;
4537 QPointF center = g->center();
4538 radialData.center.x = center.x();
4539 radialData.center.y = center.y();
4540 radialData.center.radius = g->centerRadius();
4541 QPointF focal = g->focalPoint();
4542 radialData.focal.x = focal.x();
4543 radialData.focal.y = focal.y();
4544 radialData.focal.radius = g->focalRadius();
4548 case Qt::ConicalGradientPattern:
4550 type = ConicalGradient;
4551 const QConicalGradient *g =
static_cast<
const QConicalGradient *>(brush.gradient());
4552 gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4554 auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
4555 gradient.colorTable32 = cacheInfo->buffer32;
4556#if QT_CONFIG(raster_64bit) || QT_CONFIG(raster_fp)
4557 gradient.colorTable64 = cacheInfo->buffer64;
4559 cachedGradient = std::move(cacheInfo);
4561 gradient.spread = QGradient::RepeatSpread;
4563 QConicalGradientData &conicalData = gradient.conical;
4565 QPointF center = g->center();
4566 conicalData.center.x = center.x();
4567 conicalData.center.y = center.y();
4568 conicalData.angle = qDegreesToRadians(g->angle());
4572 case Qt::Dense1Pattern:
4573 case Qt::Dense2Pattern:
4574 case Qt::Dense3Pattern:
4575 case Qt::Dense4Pattern:
4576 case Qt::Dense5Pattern:
4577 case Qt::Dense6Pattern:
4578 case Qt::Dense7Pattern:
4579 case Qt::HorPattern:
4580 case Qt::VerPattern:
4581 case Qt::CrossPattern:
4582 case Qt::BDiagPattern:
4583 case Qt::FDiagPattern:
4584 case Qt::DiagCrossPattern:
4587 tempImage =
new QImage();
4588 *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle,
true), brush.color());
4589 initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
4591 case Qt::TexturePattern:
4594 tempImage =
new QImage();
4596 if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4597 *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4599 *tempImage = brush.textureImage();
4600 initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4608 adjustSpanMethods();
4611void QSpanData::adjustSpanMethods()
4613 bitmapBlit =
nullptr;
4614 alphamapBlit =
nullptr;
4615 alphaRGBBlit =
nullptr;
4621 unclipped_blend =
nullptr;
4624 const DrawHelper &drawHelper = qDrawHelper[rasterBuffer->format];
4625 unclipped_blend = drawHelper.blendColor;
4626 bitmapBlit = drawHelper.bitmapBlit;
4627 alphamapBlit = drawHelper.alphamapBlit;
4628 alphaRGBBlit = drawHelper.alphaRGBBlit;
4629 fillRect = drawHelper.fillRect;
4632 case LinearGradient:
4633 case RadialGradient:
4634 case ConicalGradient:
4635 unclipped_blend = qBlendGradient;
4638 unclipped_blend = qBlendTexture;
4639 if (!texture.imageData)
4640 unclipped_blend =
nullptr;
4645 if (!unclipped_blend) {
4648 blend = unclipped_blend;
4649 }
else if (clip->hasRectClip) {
4650 blend = clip->clipRect.isEmpty() ?
nullptr : qt_span_fill_clipRect;
4652 blend = qt_span_fill_clipped;
4656void QSpanData::setupMatrix(
const QTransform &matrix,
int bilin)
4660 delta.translate(1.0 / 65536, 1.0 / 65536);
4662 QTransform inv = (delta * matrix).inverted();
4675 const bool affine = inv.isAffine();
4676 const qreal f1 = m11 * m11 + m21 * m21;
4677 const qreal f2 = m12 * m12 + m22 * m22;
4678 fast_matrix = affine
4681 && f1 > (1.0 / 65536)
4682 && f2 > (1.0 / 65536)
4686 adjustSpanMethods();
4689void QSpanData::initTexture(
const QImage *image,
int alpha, QTextureData::Type _type,
const QRect &sourceRect)
4691 const QImageData *d =
const_cast<QImage *>(image)->data_ptr();
4692 if (!d || d->height == 0) {
4693 texture.imageData =
nullptr;
4700 texture.bytesPerLine = 0;
4701 texture.format = QImage::Format_Invalid;
4702 texture.colorTable =
nullptr;
4703 texture.hasAlpha = alpha != 256;
4705 texture.imageData = d->data;
4706 texture.width = d->width;
4707 texture.height = d->height;
4709 if (sourceRect.isNull()) {
4712 texture.x2 = texture.width;
4713 texture.y2 = texture.height;
4715 texture.x1 = sourceRect.x();
4716 texture.y1 = sourceRect.y();
4717 texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4718 texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4721 texture.bytesPerLine = d->bytes_per_line;
4723 texture.format = d->format;
4724 texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable :
nullptr;
4725 texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4727 texture.const_alpha = alpha;
4728 texture.type = _type;
4730 adjustSpanMethods();
4734
4735
4736
4740 ProcessSpans pen_func, ProcessSpans brush_func,
4741 QSpanData *pen_data, QSpanData *brush_data)
4746 QT_FT_Span _outline[4];
4747 QT_FT_Span *outline = _outline;
4748 const int midx = rect.x() + (rect.width() + 1) / 2;
4749 const int midy = rect.y() + (rect.height() + 1) / 2;
4755 outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4756 outline[0].len = qMin(length, x - outline[0].x);
4758 outline[0].coverage = 255;
4762 outline[1].len = length;
4764 outline[1].coverage = 255;
4767 outline[2].x = outline[0].x;
4768 outline[2].len = outline[0].len;
4769 outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4770 outline[2].coverage = 255;
4774 outline[3].len = length;
4775 outline[3].y = outline[2].y;
4776 outline[3].coverage = 255;
4778 if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4779 QT_FT_Span _fill[2];
4780 QT_FT_Span *fill = _fill;
4783 fill[0].x = outline[0].x + outline[0].len - 1;
4784 fill[0].len = qMax(0, outline[1].x - fill[0].x);
4785 fill[0].y = outline[1].y;
4786 fill[0].coverage = 255;
4789 fill[1].x = outline[2].x + outline[2].len - 1;
4790 fill[1].len = qMax(0, outline[3].x - fill[1].x);
4791 fill[1].y = outline[3].y;
4792 fill[1].coverage = 255;
4794 int n = (fill[0].y >= fill[1].y ? 1 : 2);
4795 n = qt_intersect_spans(fill, n, clip);
4797 brush_func(n, fill, brush_data);
4800 int n = (outline[1].y >= outline[2].y ? 2 : 4);
4801 n = qt_intersect_spans(outline, n, clip);
4803 pen_func(n, outline, pen_data);
4808
4809
4810
4812 ProcessSpans pen_func, ProcessSpans brush_func,
4813 QSpanData *pen_data, QSpanData *brush_data)
4815 const qreal a = qreal(rect.width()) / 2;
4816 const qreal b = qreal(rect.height()) / 2;
4817 qreal d = b*b - (a*a*b) + 0.25*a*a;
4820 int y = (rect.height() + 1) / 2;
4824 while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4829 d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4830 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4831 pen_func, brush_func, pen_data, brush_data);
4836 drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4837 pen_func, brush_func, pen_data, brush_data);
4840 d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4841 const int miny = rect.height() & 0x1;
4844 d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4847 d += a*a*(-2*y + 3);
4850 drawEllipsePoints(x, y, 1, rect, clip,
4851 pen_func, brush_func, pen_data, brush_data);
4856
4857
4858
4859
4863void dumpClip(
int width,
int height,
const QClipData *clip)
4865 QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4866 clipImg.fill(0xffff0000);
4873 ((QClipData *) clip)->spans();
4875 for (
int i = 0; i < clip->count; ++i) {
4876 const QT_FT_Span *span = ((QClipData *) clip)->spans() + i;
4877 for (
int j = 0; j < span->len; ++j)
4878 clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4879 x0 = qMin(x0,
int(span->x));
4880 x1 = qMax(x1,
int(span->x + span->len - 1));
4882 y0 = qMin(y0,
int(span->y));
4883 y1 = qMax(y1,
int(span->y));
4886 static int counter = 0;
4893 fprintf(stderr,
"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4894 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