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