QtBase  v6.3.1
qpaintengineex.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 "qpaintengineex_p.h"
41 #include "qpainter_p.h"
42 #include "qstroker_p.h"
43 #include "qbezier_p.h"
44 #include <private/qpainterpath_p.h>
45 #include <private/qfontengine_p.h>
46 #include <private/qstatictext_p.h>
47 
48 #include <qvarlengtharray.h>
49 #include <qdebug.h>
50 
51 
53 
54 #if !defined(QT_MAX_CACHED_GLYPH_SIZE)
55 # define QT_MAX_CACHED_GLYPH_SIZE 64
56 #endif
57 
58 /*******************************************************************************
59  *
60  * class QVectorPath
61  *
62  */
64 {
65  if (m_hints & ShouldUseCacheHint) {
66  CacheEntry *e = m_cache;
67  while (e) {
68  if (e->data)
69  e->cleanup(e->engine, e->data);
70  CacheEntry *n = e->next;
71  delete e;
72  e = n;
73  }
74  }
75 }
76 
77 
79 {
80  if (m_hints & ControlPointRect)
81  return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
82 
83  if (m_count == 0) {
84  m_cp_rect.x1 = m_cp_rect.x2 = m_cp_rect.y1 = m_cp_rect.y2 = 0;
85  m_hints |= ControlPointRect;
86  return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
87  }
88  Q_ASSERT(m_points && m_count > 0);
89 
90  const qreal *pts = m_points;
91  m_cp_rect.x1 = m_cp_rect.x2 = *pts;
92  ++pts;
93  m_cp_rect.y1 = m_cp_rect.y2 = *pts;
94  ++pts;
95 
96  const qreal *epts = m_points + (m_count << 1);
97  while (pts < epts) {
98  qreal x = *pts;
99  if (x < m_cp_rect.x1) m_cp_rect.x1 = x;
100  else if (x > m_cp_rect.x2) m_cp_rect.x2 = x;
101  ++pts;
102 
103  qreal y = *pts;
104  if (y < m_cp_rect.y1) m_cp_rect.y1 = y;
105  else if (y > m_cp_rect.y2) m_cp_rect.y2 = y;
106  ++pts;
107  }
108 
109  m_hints |= ControlPointRect;
110  return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
111 }
112 
113 
116  Q_ASSERT(!lookupCacheData(engine));
117  if ((m_hints & IsCachedHint) == 0) {
118  m_cache = nullptr;
119  m_hints |= IsCachedHint;
120  }
121  CacheEntry *e = new CacheEntry;
122  e->engine = engine;
123  e->data = data;
124  e->cleanup = cleanup;
125  e->next = m_cache;
126  m_cache = e;
127  return m_cache;
128 }
129 
130 
132 {
133  Q_ASSERT(path.d_func());
134  return path.d_func()->vectorPath();
135 }
136 
137 #ifndef QT_NO_DEBUG_STREAM
138 QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path)
139 {
140  QDebugStateSaver saver(s);
141  QRectF rf = path.controlPointRect();
142  s << "QVectorPath(size:" << path.elementCount()
143  << " hints:" << Qt::hex << path.hints()
144  << rf << ')';
145  return s;
146 }
147 #endif
148 
149 /*******************************************************************************
150  *
151  * class QPaintEngineExPrivate:
152  *
153  */
154 
155 
160 };
161 
162 
164  : dasher(&stroker),
165  strokeHandler(nullptr),
166  activeStroker(nullptr),
167  strokerPen(Qt::NoPen)
168 {
169 }
170 
171 
173 {
174  delete strokeHandler;
175 }
176 
177 
179 {
180  Q_Q(QPaintEngineEx);
181 
182  QPainter *p = q->painter();
183  if (!p || !p->d_ptr)
184  return;
185 
186  const QList<QPainterClipInfo> &clipInfo = p->d_ptr->state->clipInfo;
187 
188  QTransform transform = q->state()->matrix;
189 
190  for (const QPainterClipInfo &info : clipInfo) {
191 
192  if (info.matrix != q->state()->matrix) {
193  q->state()->matrix = info.matrix;
194  q->transformChanged();
195  }
196 
197  switch (info.clipType) {
199  q->clip(info.region, info.operation);
200  break;
202  q->clip(info.path, info.operation);
203  break;
205  q->clip(info.rect, info.operation);
206  break;
208  qreal right = info.rectf.x() + info.rectf.width();
209  qreal bottom = info.rectf.y() + info.rectf.height();
210  qreal pts[] = { info.rectf.x(), info.rectf.y(),
211  right, info.rectf.y(),
212  right, bottom,
213  info.rectf.x(), bottom };
214  QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
215  q->clip(vp, info.operation);
216  break;
217  }
218  }
219  }
220 
221  if (transform != q->state()->matrix) {
222  q->state()->matrix = transform;
223  q->transformChanged();
224  }
225 }
226 
227 
229 {
230  Q_Q(const QPaintEngineEx);
231 
232  QPainter *p = q->painter();
233  if (!p || !p->d_ptr)
234  return false;
235 
236  return !p->d_ptr->state->clipInfo.isEmpty();
237 }
238 
239 /*******************************************************************************
240  *
241  * class QPaintEngineEx:
242  *
243  */
244 
245 static const QPainterPath::ElementType qpaintengineex_ellipse_types[] = {
250 
254 
258 
262 };
263 
264 static const QPainterPath::ElementType qpaintengineex_line_types_16[] = {
281 };
282 
283 static const QPainterPath::ElementType qpaintengineex_rect4_types_32[] = {
316 };
317 
318 
319 static const QPainterPath::ElementType qpaintengineex_roundedrect_types[] = {
337 };
338 
339 
340 
341 static void qpaintengineex_moveTo(qreal x, qreal y, void *data) {
342  ((StrokeHandler *) data)->pts.add(x);
343  ((StrokeHandler *) data)->pts.add(y);
345 }
346 
347 static void qpaintengineex_lineTo(qreal x, qreal y, void *data) {
348  ((StrokeHandler *) data)->pts.add(x);
349  ((StrokeHandler *) data)->pts.add(y);
351 }
352 
353 static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data) {
354  ((StrokeHandler *) data)->pts.add(c1x);
355  ((StrokeHandler *) data)->pts.add(c1y);
357 
358  ((StrokeHandler *) data)->pts.add(c2x);
359  ((StrokeHandler *) data)->pts.add(c2y);
361 
362  ((StrokeHandler *) data)->pts.add(ex);
363  ((StrokeHandler *) data)->pts.add(ey);
365 }
366 
368  : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures)
369 {
370  extended = true;
371 }
372 
374  : QPaintEngine(data, AllFeatures)
375 {
376  extended = true;
377 }
378 
380 {
381  if (!orig)
382  return new QPainterState;
383  return new QPainterState(orig);
384 }
385 
386 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
387 
388 void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
389 {
390 #ifdef QT_DEBUG_DRAW
391  qDebug() << "QPaintEngineEx::stroke()" << inPen;
392 #endif
393 
394  Q_D(QPaintEngineEx);
395 
396  if (path.isEmpty())
397  return;
398 
399  if (!d->strokeHandler) {
400  d->strokeHandler = new StrokeHandler(path.elementCount()+4);
401  d->stroker.setMoveToHook(qpaintengineex_moveTo);
402  d->stroker.setLineToHook(qpaintengineex_lineTo);
403  d->stroker.setCubicToHook(qpaintengineex_cubicTo);
404  }
405 
406  QRectF clipRect;
407  QPen pen = inPen;
408  if (pen.style() > Qt::SolidLine) {
409  QRectF cpRect = path.controlPointRect();
410  const QTransform &xf = state()->matrix;
411  if (pen.isCosmetic()) {
412  clipRect = d->exDeviceRect;
413  cpRect.translate(xf.dx(), xf.dy());
414  } else {
415  clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
416  }
417  // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
418  qreal pw = pen.widthF() ? pen.widthF() : 1;
419  QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
420  qreal extent = qMax(extentRect.width(), extentRect.height());
421  qreal patternLength = 0;
422  const QList<qreal> pattern = pen.dashPattern();
423  const int patternSize = qMin(pattern.size(), 32);
424  for (int i = 0; i < patternSize; i++)
425  patternLength += qMax(pattern.at(i), qreal(0));
426  patternLength *= pw;
427  if (qFuzzyIsNull(patternLength)) {
428  pen.setStyle(Qt::NoPen);
429  } else if (extent / patternLength > QDashStroker::repetitionLimit()) {
430  // approximate stream of tiny dashes with semi-transparent solid line
431  pen.setStyle(Qt::SolidLine);
432  QColor color(pen.color());
433  color.setAlpha(color.alpha() / 2);
434  pen.setColor(color);
435  }
436  }
437 
438  if (!qpen_fast_equals(pen, d->strokerPen)) {
439  d->strokerPen = pen;
440  d->stroker.setJoinStyle(pen.joinStyle());
441  d->stroker.setCapStyle(pen.capStyle());
442  d->stroker.setMiterLimit(pen.miterLimit());
443  qreal penWidth = pen.widthF();
444  if (penWidth == 0)
445  d->stroker.setStrokeWidth(1);
446  else
447  d->stroker.setStrokeWidth(penWidth);
448 
449  Qt::PenStyle style = pen.style();
450  if (style == Qt::SolidLine) {
451  d->activeStroker = &d->stroker;
452  } else if (style == Qt::NoPen) {
453  d->activeStroker = nullptr;
454  } else {
455  d->dasher.setDashPattern(pen.dashPattern());
456  d->dasher.setDashOffset(pen.dashOffset());
457  d->activeStroker = &d->dasher;
458  }
459  }
460 
461  if (!d->activeStroker) {
462  return;
463  }
464 
465  if (!clipRect.isNull())
466  d->activeStroker->setClipRect(clipRect);
467 
468  if (d->activeStroker == &d->stroker)
469  d->stroker.setForceOpen(path.hasExplicitOpen());
470 
471  const QPainterPath::ElementType *types = path.elements();
472  const qreal *points = path.points();
473  int pointCount = path.elementCount();
474 
475  const qreal *lastPoint = points + (pointCount<<1);
476 
477  d->strokeHandler->types.reset();
478  d->strokeHandler->pts.reset();
479 
480  // Some engines might decide to optimize for the non-shape hint later on...
482 
483  if (path.elementCount() > 2)
485 
486  if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin)
488 
489  // ### Perspective Xforms are currently not supported...
490  if (!pen.isCosmetic()) {
491  // We include cosmetic pens in this case to avoid having to
492  // change the current transform. Normal transformed,
493  // non-cosmetic pens will be transformed as part of fill
494  // later, so they are also covered here..
495  d->activeStroker->setCurveThresholdFromTransform(state()->matrix);
496  d->activeStroker->begin(d->strokeHandler);
497  if (types) {
498  while (points < lastPoint) {
499  switch (*types) {
501  d->activeStroker->moveTo(points[0], points[1]);
502  points += 2;
503  ++types;
504  break;
506  d->activeStroker->lineTo(points[0], points[1]);
507  points += 2;
508  ++types;
509  break;
511  d->activeStroker->cubicTo(points[0], points[1],
512  points[2], points[3],
513  points[4], points[5]);
514  points += 6;
515  types += 3;
517  break;
518  default:
519  break;
520  }
521  }
522  if (path.hasImplicitClose())
523  d->activeStroker->lineTo(path.points()[0], path.points()[1]);
524 
525  } else {
526  d->activeStroker->moveTo(points[0], points[1]);
527  points += 2;
528  while (points < lastPoint) {
529  d->activeStroker->lineTo(points[0], points[1]);
530  points += 2;
531  }
532  if (path.hasImplicitClose())
533  d->activeStroker->lineTo(path.points()[0], path.points()[1]);
534  }
535  d->activeStroker->end();
536 
537  if (!d->strokeHandler->types.size()) // an empty path...
538  return;
539 
540  QVectorPath strokePath(d->strokeHandler->pts.data(),
541  d->strokeHandler->types.size(),
542  d->strokeHandler->types.data(),
543  flags);
544  fill(strokePath, pen.brush());
545  } else {
546  // For cosmetic pens we need a bit of trickery... We to process xform the input points
547  if (state()->matrix.type() >= QTransform::TxProject) {
548  QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath());
549  d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform());
550  } else {
551  d->activeStroker->setCurveThresholdFromTransform(QTransform());
552  d->activeStroker->begin(d->strokeHandler);
553  if (types) {
554  while (points < lastPoint) {
555  switch (*types) {
557  QPointF pt = (*(const QPointF *) points) * state()->matrix;
558  d->activeStroker->moveTo(pt.x(), pt.y());
559  points += 2;
560  ++types;
561  break;
562  }
564  QPointF pt = (*(const QPointF *) points) * state()->matrix;
565  d->activeStroker->lineTo(pt.x(), pt.y());
566  points += 2;
567  ++types;
568  break;
569  }
571  QPointF c1 = ((const QPointF *) points)[0] * state()->matrix;
572  QPointF c2 = ((const QPointF *) points)[1] * state()->matrix;
573  QPointF e = ((const QPointF *) points)[2] * state()->matrix;
574  d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
575  points += 6;
576  types += 3;
578  break;
579  }
580  default:
581  break;
582  }
583  }
584  if (path.hasImplicitClose()) {
585  QPointF pt = * ((const QPointF *) path.points()) * state()->matrix;
586  d->activeStroker->lineTo(pt.x(), pt.y());
587  }
588 
589  } else {
590  QPointF p = ((const QPointF *)points)[0] * state()->matrix;
591  d->activeStroker->moveTo(p.x(), p.y());
592  points += 2;
593  while (points < lastPoint) {
594  QPointF p = ((const QPointF *)points)[0] * state()->matrix;
595  d->activeStroker->lineTo(p.x(), p.y());
596  points += 2;
597  }
598  if (path.hasImplicitClose())
599  d->activeStroker->lineTo(p.x(), p.y());
600  }
601  d->activeStroker->end();
602  }
603 
604  QVectorPath strokePath(d->strokeHandler->pts.data(),
605  d->strokeHandler->types.size(),
606  d->strokeHandler->types.data(),
607  flags);
608 
610  state()->matrix = QTransform();
612 
613  QBrush brush = pen.brush();
615  brush.setTransform(brush.transform() * xform);
616 
617  fill(strokePath, brush);
618 
619  state()->matrix = xform;
621  }
622 }
623 
625 {
626  const QBrush &brush = state()->brush;
628  fill(path, brush);
629 
630  const QPen &pen = state()->pen;
631  if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush)
632  stroke(path, pen);
633 }
634 
635 
637 {
638  qreal right = r.x() + r.width();
639  qreal bottom = r.y() + r.height();
640  qreal pts[] = { qreal(r.x()), qreal(r.y()),
641  right, qreal(r.y()),
642  right, bottom,
643  qreal(r.x()), bottom,
644  qreal(r.x()), qreal(r.y()) };
645  QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
646  clip(vp, op);
647 }
648 
650 {
651  const auto rectsInRegion = region.rectCount();
652  if (rectsInRegion == 1) {
653  clip(*region.begin(), op);
654  } else if (rectsInRegion <= 32) {
655  qreal pts[2*32*4];
656  int pos = 0;
657  for (QRect r : region) {
658  qreal x1 = r.x();
659  qreal y1 = r.y();
660  qreal x2 = r.x() + r.width();
661  qreal y2 = r.y() + r.height();
662 
663  pts[pos++] = x1;
664  pts[pos++] = y1;
665 
666  pts[pos++] = x2;
667  pts[pos++] = y1;
668 
669  pts[pos++] = x2;
670  pts[pos++] = y2;
671 
672  pts[pos++] = x1;
673  pts[pos++] = y2;
674  }
675  QVectorPath vp(pts, rectsInRegion * 4, qpaintengineex_rect4_types_32);
676  clip(vp, op);
677  } else {
678  QVarLengthArray<qreal> pts(rectsInRegion * 2 * 4);
680  int ppos = 0;
681  int tpos = 0;
682 
683  for (QRect r : region) {
684  qreal x1 = r.x();
685  qreal y1 = r.y();
686  qreal x2 = r.x() + r.width();
687  qreal y2 = r.y() + r.height();
688 
689  pts[ppos++] = x1;
690  pts[ppos++] = y1;
691 
692  pts[ppos++] = x2;
693  pts[ppos++] = y1;
694 
695  pts[ppos++] = x2;
696  pts[ppos++] = y2;
697 
698  pts[ppos++] = x1;
699  pts[ppos++] = y2;
700 
705  }
706 
707  QVectorPath vp(pts.data(), rectsInRegion * 4, types.data());
708  clip(vp, op);
709  }
710 
711 }
712 
714 {
715  if (path.isEmpty()) {
716  QVectorPath vp(nullptr, 0);
717  clip(vp, op);
718  } else {
720  }
721 }
722 
724 {
725  qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(),
726  r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() };
727  QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
728  fill(vp, brush);
729 }
730 
732 {
733  fillRect(r, QBrush(color));
734 }
735 
736 void QPaintEngineEx::drawRects(const QRect *rects, int rectCount)
737 {
738  for (int i=0; i<rectCount; ++i) {
739  const QRect &r = rects[i];
740  // ### Is there a one off here?
741  qreal right = r.x() + r.width();
742  qreal bottom = r.y() + r.height();
743  qreal pts[] = { qreal(r.x()), qreal(r.y()),
744  right, qreal(r.y()),
745  right, bottom,
746  qreal(r.x()), bottom,
747  qreal(r.x()), qreal(r.y()) };
748  QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
749  draw(vp);
750  }
751 }
752 
753 void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount)
754 {
755  for (int i=0; i<rectCount; ++i) {
756  const QRectF &r = rects[i];
757  qreal right = r.x() + r.width();
758  qreal bottom = r.y() + r.height();
759  qreal pts[] = { r.x(), r.y(),
760  right, r.y(),
761  right, bottom,
762  r.x(), bottom,
763  r.x(), r.y() };
764  QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
765  draw(vp);
766  }
767 }
768 
769 
770 void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
772 {
773  qreal x1 = rect.left();
774  qreal x2 = rect.right();
775  qreal y1 = rect.top();
776  qreal y2 = rect.bottom();
777 
778  if (mode == Qt::RelativeSize) {
779  xRadius = xRadius * rect.width() / 200.;
780  yRadius = yRadius * rect.height() / 200.;
781  }
782 
783  xRadius = qMin(xRadius, rect.width() / 2);
784  yRadius = qMin(yRadius, rect.height() / 2);
785 
786  qreal pts[] = {
787  x1 + xRadius, y1, // MoveTo
788  x2 - xRadius, y1, // LineTo
789  x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
790  x2, y1 + (1 - KAPPA) * yRadius,
791  x2, y1 + yRadius,
792  x2, y2 - yRadius, // LineTo
793  x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
794  x2 - (1 - KAPPA) * xRadius, y2,
795  x2 - xRadius, y2,
796  x1 + xRadius, y2, // LineTo
797  x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
798  x1, y2 - (1 - KAPPA) * yRadius,
799  x1, y2 - yRadius,
800  x1, y1 + yRadius, // LineTo
801  x1, y1 + (1 - KAPPA) * yRadius, // CurveTo
802  x1 + (1 - KAPPA) * xRadius, y1,
803  x1 + xRadius, y1
804  };
805 
806  QVectorPath path(pts, 17, qpaintengineex_roundedrect_types, QVectorPath::RoundedRectHint);
807  draw(path);
808 }
809 
810 
811 
812 void QPaintEngineEx::drawLines(const QLine *lines, int lineCount)
813 {
814  int elementCount = lineCount << 1;
815  while (elementCount > 0) {
816  int count = qMin(elementCount, 32);
817 
818  qreal pts[64];
819  int count2 = count<<1;
820  for (int i=0; i<count2; ++i)
821  pts[i] = ((const int *) lines)[i];
822 
823  QVectorPath path(pts, count, qpaintengineex_line_types_16, QVectorPath::LinesHint);
824  stroke(path, state()->pen);
825 
826  elementCount -= 32;
827  lines += 16;
828  }
829 }
830 
831 void QPaintEngineEx::drawLines(const QLineF *lines, int lineCount)
832 {
833  int elementCount = lineCount << 1;
834  while (elementCount > 0) {
835  int count = qMin(elementCount, 32);
836 
837  QVectorPath path((const qreal *) lines, count, qpaintengineex_line_types_16,
839  stroke(path, state()->pen);
840 
841  elementCount -= 32;
842  lines += 16;
843  }
844 }
845 
847 {
848  qreal pts[26]; // QPointF[13] without constructors...
849  union {
850  qreal *ptr;
851  QPointF *points;
852  } x;
853  x.ptr = pts;
854 
855  int point_count = 0;
856  x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
857  if (point_count == 0)
858  return;
859  QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
860  draw(vp);
861 }
862 
864 {
865  drawEllipse(QRectF(r));
866 }
867 
869 {
870  if (!path.isEmpty())
872 }
873 
874 
875 void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
876 {
877  QPen pen = state()->pen;
878  if (pen.capStyle() == Qt::FlatCap)
880 
881  if (pen.brush().isOpaque()) {
882  while (pointCount > 0) {
883  int count = qMin(pointCount, 16);
884  qreal pts[64];
885  int oset = -1;
886  for (int i=0; i<count; ++i) {
887  pts[++oset] = points[i].x();
888  pts[++oset] = points[i].y();
889  pts[++oset] = points[i].x() + 1/63.;
890  pts[++oset] = points[i].y();
891  }
892  QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
893  stroke(path, pen);
894  pointCount -= 16;
895  points += 16;
896  }
897  } else {
898  for (int i=0; i<pointCount; ++i) {
899  qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + qreal(1/63.), points[i].y() };
900  QVectorPath path(pts, 2, nullptr);
901  stroke(path, pen);
902  }
903  }
904 }
905 
906 void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
907 {
908  QPen pen = state()->pen;
909  if (pen.capStyle() == Qt::FlatCap)
911 
912  if (pen.brush().isOpaque()) {
913  while (pointCount > 0) {
914  int count = qMin(pointCount, 16);
915  qreal pts[64];
916  int oset = -1;
917  for (int i=0; i<count; ++i) {
918  pts[++oset] = points[i].x();
919  pts[++oset] = points[i].y();
920  pts[++oset] = points[i].x() + 1/63.;
921  pts[++oset] = points[i].y();
922  }
923  QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
924  stroke(path, pen);
925  pointCount -= 16;
926  points += 16;
927  }
928  } else {
929  for (int i=0; i<pointCount; ++i) {
930  qreal pts[] = { qreal(points[i].x()), qreal(points[i].y()),
931  qreal(points[i].x() +1/63.), qreal(points[i].y()) };
932  QVectorPath path(pts, 2, nullptr);
933  stroke(path, pen);
934  }
935  }
936 }
937 
938 
940 {
941  Q_ASSUME(pointCount >= 2);
942  QVectorPath path((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
943 
944  if (mode == PolylineMode)
945  stroke(path, state()->pen);
946  else
947  draw(path);
948 }
949 
951 {
952  Q_ASSUME(pointCount >= 2);
953  int count = pointCount<<1;
955 
956  for (int i=0; i<count; ++i)
957  pts[i] = ((const int *) points)[i];
958 
959  QVectorPath path(pts.data(), pointCount, nullptr, QVectorPath::polygonFlags(mode));
960 
961  if (mode == PolylineMode)
962  stroke(path, state()->pen);
963  else
964  draw(path);
965 
966 }
967 
969 {
970  drawPixmap(QRectF(pos, pm.deviceIndependentSize()), pm, pm.rect());
971 }
972 
974 {
975  drawImage(QRectF(pos, image.deviceIndependentSize()), image, image.rect());
976 }
977 
979 {
980  QBrush brush(state()->pen.color(), pixmap);
981  QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
982  if (!qFuzzyCompare(pixmap.devicePixelRatio(), qreal(1.0)))
983  xform.scale(1.0/pixmap.devicePixelRatio(), 1.0/pixmap.devicePixelRatio());
984  brush.setTransform(xform);
985 
986  qreal pts[] = { r.x(), r.y(),
987  r.x() + r.width(), r.y(),
988  r.x() + r.width(), r.y() + r.height(),
989  r.x(), r.y() + r.height() };
990 
991  QVectorPath path(pts, 4, nullptr, QVectorPath::RectangleHint);
992  fill(path, brush);
993 }
994 
995 void QPaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount,
996  const QPixmap &pixmap, QPainter::PixmapFragmentHints /*hints*/)
997 {
998  if (pixmap.isNull())
999  return;
1000 
1001  qreal oldOpacity = state()->opacity;
1002  QTransform oldTransform = state()->matrix;
1003 
1004  for (int i = 0; i < fragmentCount; ++i) {
1005  QTransform transform = oldTransform;
1006  transform.translate(fragments[i].x, fragments[i].y);
1007  transform.rotate(fragments[i].rotation);
1008  state()->opacity = oldOpacity * fragments[i].opacity;
1009  state()->matrix = transform;
1010  opacityChanged();
1011  transformChanged();
1012 
1013  qreal w = fragments[i].scaleX * fragments[i].width;
1014  qreal h = fragments[i].scaleY * fragments[i].height;
1015  QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
1016  fragments[i].width, fragments[i].height);
1017  drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect);
1018  }
1019 
1020  state()->opacity = oldOpacity;
1021  state()->matrix = oldTransform;
1022  opacityChanged();
1023  transformChanged();
1024 }
1025 
1027 {
1029 }
1030 
1031 
1033 {
1034  // do nothing...
1035 }
1036 
1038 {
1039  const qreal *points = path.points();
1040  const QPainterPath::ElementType *types = path.elements();
1041 
1042  QPainterPath p;
1043  if (types) {
1044  int id = 0;
1045  for (int i=0; i<path.elementCount(); ++i) {
1046  switch(types[i]) {
1048  p.moveTo(QPointF(points[id], points[id+1]));
1049  id+=2;
1050  break;
1052  p.lineTo(QPointF(points[id], points[id+1]));
1053  id+=2;
1054  break;
1056  QPointF p1(points[id], points[id+1]);
1057  QPointF p2(points[id+2], points[id+3]);
1058  QPointF p3(points[id+4], points[id+5]);
1059  p.cubicTo(p1, p2, p3);
1060  id+=6;
1061  break;
1062  }
1064  ;
1065  break;
1066  }
1067  }
1068  } else {
1069  p.moveTo(QPointF(points[0], points[1]));
1070  int id = 2;
1071  for (int i=1; i<path.elementCount(); ++i) {
1072  p.lineTo(QPointF(points[id], points[id+1]));
1073  id+=2;
1074  }
1075  }
1076  if (path.hints() & QVectorPath::WindingFill)
1077  p.setFillRule(Qt::WindingFill);
1078 
1079  return p;
1080 }
1081 
1083 {
1085  path.setFillRule(Qt::WindingFill);
1086 
1087  if (staticTextItem->numGlyphs == 0)
1088  return;
1089 
1090  QFontEngine *fontEngine = staticTextItem->fontEngine();
1091  fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
1092  staticTextItem->numGlyphs, &path, { });
1093  if (!path.isEmpty()) {
1094  QPainterState *s = state();
1095  QPainter::RenderHints oldHints = s->renderHints;
1096  bool changedHints = false;
1097  if (bool(oldHints & QPainter::TextAntialiasing)
1098  && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
1099  && !bool(oldHints & QPainter::Antialiasing)) {
1100  s->renderHints |= QPainter::Antialiasing;
1102  changedHints = true;
1103  }
1104 
1105  fill(qtVectorPathForPath(path), s->pen.brush());
1106 
1107  if (changedHints) {
1108  s->renderHints = oldHints;
1110  }
1111  }
1112 }
1113 
1115 {
1116  return false;
1117 }
1118 
1120 {
1121  if (fontEngine->glyphFormat == QFontEngine::Format_ARGB)
1122  return true;
1123 
1124  static const int maxCachedGlyphSizeSquared = std::pow([]{
1125  if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE"))
1126  return env;
1127  return QT_MAX_CACHED_GLYPH_SIZE;
1128  }(), 2);
1129 
1130  qreal pixelSize = fontEngine->fontDef.pixelSize;
1131  return (pixelSize * pixelSize * qAbs(m.determinant())) <= maxCachedGlyphSizeSquared;
1132 }
1133 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:66
bool isOpaque() const
Definition: qbrush.cpp:863
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
static int repetitionLimit()
Definition: qstroker_p.h:271
operator<<(QDataStream &ds, qfloat16 f)
Definition: qfloat16.cpp:327
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
QFontDef fontDef
GlyphFormat glyphFormat
@ NoAntialias
Definition: qfont.h:81
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:215
The QLine class provides a two-dimensional vector using integer precision.
Definition: qline.h:53
virtual void drawRects(const QRect *rects, int rectCount) override
virtual void renderHintsChanged()=0
virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, QFlags< QPainter::PixmapFragmentHint > hints)
virtual void stroke(const QVectorPath &path, const QPen &pen)
virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
virtual void drawEllipse(const QRectF &r) override
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor) override=0
virtual void drawLines(const QLine *lines, int lineCount) override
virtual void clip(const QVectorPath &path, Qt::ClipOperation op)=0
virtual void fill(const QVectorPath &path, const QBrush &brush)=0
virtual void opacityChanged()=0
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override=0
virtual QPainterState * createState(QPainterState *orig) const
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override
virtual void drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
virtual bool requiresPretransformedGlyphPositions(QFontEngine *fontEngine, const QTransform &m) const
virtual void draw(const QVectorPath &path)
virtual void fillRect(const QRectF &rect, const QBrush &brush)
virtual void updateState(const QPaintEngineState &state) override
virtual void transformChanged()=0
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 drawPath(const QPainterPath &path) override
virtual void drawStaticTextItem(QStaticTextItem *)
QPainterState * state()
StrokeHandler * strokeHandler
bool hasClipOperations() const
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:87
QPaintEngineState * state
Definition: qpaintengine.h:234
The QPaintEngineState class provides information about the active paint engine's current state....
Definition: qpaintengine.h:268
This class is used in conjunction with the QPainter::drawPixmapFragments() function to specify how a ...
Definition: qpainter.h:99
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:82
@ Antialiasing
Definition: qpainter.h:88
@ TextAntialiasing
Definition: qpainter.h:89
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
QBrush brush
Definition: qpainter_p.h:158
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
void setCapStyle(Qt::PenCapStyle pcs)
Definition: qpen.cpp:712
qreal widthF() const
Definition: qpen.cpp:634
void setStyle(Qt::PenStyle)
[0]
QList< qreal > dashPattern() const
Definition: qpen.cpp:456
bool isCosmetic() const
Definition: qpen.cpp:819
QColor color() const
Definition: qpen.cpp:754
Qt::PenCapStyle capStyle() const
Definition: qpen.cpp:698
void setColor(const QColor &color)
Definition: qpen.cpp:767
Qt::PenJoinStyle joinStyle() const
Definition: qpen.cpp:725
qreal miterLimit() const
Definition: qpen.cpp:584
QBrush brush() const
Definition: qpen.cpp:777
qreal dashOffset() const
Definition: qpen.cpp:542
Qt::PenStyle style() const
Definition: qpen.cpp:421
The QPixmap class is an off-screen image representation that can be used as a paint device.
Definition: qpixmap.h:63
QSizeF deviceIndependentSize() const
Definition: qpixmap.cpp:659
QRect rect() const
Definition: qpixmap.cpp:540
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
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:52
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
constexpr qreal height() const noexcept
Definition: qrect.h:741
constexpr qreal width() const noexcept
Definition: qrect.h:738
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Definition: qrect.h:822
constexpr bool isNull() const noexcept
Definition: qrect.h:667
constexpr void translate(qreal dx, qreal dy) noexcept
Definition: qrect.h:747
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:59
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:63
int rectCount() const noexcept
const_iterator begin() const noexcept
glyph_t * glyphs
QFixedPoint * glyphPositions
Definition: qstatictext_p.h:98
QFontEngine * fontEngine() const
Definition: qstatictext_p.h:95
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
QTransform & scale(qreal sx, qreal sy)
Definition: qtransform.cpp:460
qreal dx() const
Definition: qtransform.h:262
QPoint map(const QPoint &p) const
static QTransform fromTranslate(qreal dx, qreal dy)
Definition: qtransform.cpp:437
QTransform inverted(bool *invertible=nullptr) const
Definition: qtransform.cpp:339
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis)
Definition: qtransform.cpp:588
QTransform & translate(qreal dx, qreal dy)
Definition: qtransform.cpp:392
QRect mapRect(const QRect &) const
qreal dy() const
Definition: qtransform.h:266
T * data() noexcept
static uint polygonFlags(QPaintEngine::PolygonDrawMode mode)
CacheEntry * lookupCacheData(QPaintEngineEx *engine) const
CacheEntry * addCacheData(QPaintEngineEx *engine, void *data, qvectorpath_cache_cleanup cleanup) const
QRectF controlPointRect() const
float rotation
QPixmap p2
QPixmap p1
[0]
double e
set reserve(20000)
rect
[4]
backing_store_ptr info
[4]
Definition: jmemsys.h:161
Definition: qnamespace.h:55
SizeMode
Definition: qnamespace.h:1161
@ RelativeSize
Definition: qnamespace.h:1163
QTextStream & hex(QTextStream &stream)
ClipOperation
Definition: qnamespace.h:1330
PenStyle
Definition: qnamespace.h:1111
@ SolidLine
Definition: qnamespace.h:1113
@ NoPen
Definition: qnamespace.h:1112
@ RoundJoin
Definition: qnamespace.h:1134
@ SolidPattern
Definition: qnamespace.h:1141
@ NoBrush
Definition: qnamespace.h:1140
@ WindingFill
Definition: qnamespace.h:1322
@ SquareCap
Definition: qnamespace.h:1126
@ RoundCap
Definition: qnamespace.h:1127
@ FlatCap
Definition: qnamespace.h:1125
Definition: brush.cpp:52
Definition: image.cpp:51
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 cleanup[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
#define KAPPA
Definition: qbezier.cpp:328
#define Q_ASSUME(Expr)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition: qfloat16.h:233
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition: qfloat16.h:249
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
unsigned int uint
Definition: qglobal.h:334
#define qDebug
[1]
Definition: qlogging.h:177
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLint GLsizei width
GLuint color
[2]
GLint GLint bottom
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat n
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
Definition: qopenglext.h:11564
GLfixed GLfixed GLint GLint GLfixed points
Definition: qopenglext.h:5206
GLfixed GLfixed GLfixed y2
Definition: qopenglext.h:5231
GLuint GLenum matrix
Definition: qopenglext.h:11564
GLfixed GLfixed x2
Definition: qopenglext.h:5231
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLenum GLenum GLenum scale
Definition: qopenglext.h:10817
GLubyte * pattern
Definition: qopenglext.h:2744
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
#define QT_MAX_CACHED_GLYPH_SIZE
Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
Qt::BrushStyle qbrush_style(const QBrush &b)
Definition: qpainter_p.h:99
bool qpen_fast_equals(const QPen &a, const QPen &b)
Definition: qpainter_p.h:89
Qt::PenStyle qpen_style(const QPen &p)
Definition: qpainter_p.h:92
QBrush qpen_brush(const QPen &p)
Definition: qpainter_p.h:90
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition: qstroker.cpp:852
void(* qvectorpath_cache_cleanup)(QPaintEngineEx *engine, void *data)
Definition: qvectorpath_p.h:67
QObject::connect nullptr
MyCustomStruct c2
QTransform xform
[18]
widget render & pixmap
uint styleStrategy
Definition: qfont_p.h:99
qreal pixelSize
Definition: qfont_p.h:96
QDataBuffer< qreal > pts
StrokeHandler(int reserve)
QDataBuffer< QPainterPath::ElementType > types