Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpaintengineex.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpaintengineex_p.h"
5#include "qpainter_p.h"
6#include "qstroker_p.h"
7#include "qbezier_p.h"
8#include <private/qpainterpath_p.h>
9#include <private/qfontengine_p.h>
10#include <private/qstatictext_p.h>
11
12#include <qvarlengtharray.h>
13#include <qdebug.h>
14
15
17
18#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
19# define QT_MAX_CACHED_GLYPH_SIZE 64
20#endif
21
22/*******************************************************************************
23 *
24 * class QVectorPath
25 *
26 */
28{
29 if (m_hints & ShouldUseCacheHint) {
30 CacheEntry *e = m_cache;
31 while (e) {
32 if (e->data)
33 e->cleanup(e->engine, e->data);
34 CacheEntry *n = e->next;
35 delete e;
36 e = n;
37 }
38 }
39}
40
41
43{
44 if (m_hints & ControlPointRect)
45 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
46
47 if (m_count == 0) {
48 m_cp_rect.x1 = m_cp_rect.x2 = m_cp_rect.y1 = m_cp_rect.y2 = 0;
49 m_hints |= ControlPointRect;
50 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
51 }
52 Q_ASSERT(m_points && m_count > 0);
53
54 const qreal *pts = m_points;
55 m_cp_rect.x1 = m_cp_rect.x2 = *pts;
56 ++pts;
57 m_cp_rect.y1 = m_cp_rect.y2 = *pts;
58 ++pts;
59
60 const qreal *epts = m_points + (m_count << 1);
61 while (pts < epts) {
62 qreal x = *pts;
63 if (x < m_cp_rect.x1) m_cp_rect.x1 = x;
64 else if (x > m_cp_rect.x2) m_cp_rect.x2 = x;
65 ++pts;
66
67 qreal y = *pts;
68 if (y < m_cp_rect.y1) m_cp_rect.y1 = y;
69 else if (y > m_cp_rect.y2) m_cp_rect.y2 = y;
70 ++pts;
71 }
72
73 m_hints |= ControlPointRect;
74 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
75}
76
77
79 qvectorpath_cache_cleanup cleanup) const{
81 if ((m_hints & IsCachedHint) == 0) {
82 m_cache = nullptr;
83 m_hints |= IsCachedHint;
84 }
85 CacheEntry *e = new CacheEntry;
86 e->engine = engine;
87 e->data = data;
88 e->cleanup = cleanup;
89 e->next = m_cache;
90 m_cache = e;
91 return m_cache;
92}
93
94
96{
97 Q_ASSERT(path.d_func());
98 return path.d_func()->vectorPath();
99}
100
101#ifndef QT_NO_DEBUG_STREAM
102QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path)
103{
104 QDebugStateSaver saver(s);
105 QRectF rf = path.controlPointRect();
106 s << "QVectorPath(size:" << path.elementCount()
107 << " hints:" << Qt::hex << path.hints()
108 << rf << ')';
109 return s;
110}
111#endif
112
113/*******************************************************************************
114 *
115 * class QPaintEngineExPrivate:
116 *
117 */
118
119
122 QDataBuffer<qreal> pts;
123 QDataBuffer<QPainterPath::ElementType> types;
124};
125
126
128 : dasher(&stroker),
129 strokeHandler(nullptr),
130 activeStroker(nullptr),
131 strokerPen(Qt::NoPen)
132{
133}
134
135
140
141
143{
144 Q_Q(QPaintEngineEx);
145
146 QPainter *p = q->painter();
147 if (!p || !p->d_ptr)
148 return;
149
150 const QList<QPainterClipInfo> &clipInfo = p->d_ptr->state->clipInfo;
151
152 QTransform transform = q->state()->matrix;
153
154 for (const QPainterClipInfo &info : clipInfo) {
155
156 if (info.matrix != q->state()->matrix) {
157 q->state()->matrix = info.matrix;
158 q->transformChanged();
159 }
160
161 switch (info.clipType) {
163 q->clip(info.region, info.operation);
164 break;
166 q->clip(info.path, info.operation);
167 break;
169 q->clip(info.rect, info.operation);
170 break;
172 qreal right = info.rectf.x() + info.rectf.width();
173 qreal bottom = info.rectf.y() + info.rectf.height();
174 qreal pts[] = { info.rectf.x(), info.rectf.y(),
175 right, info.rectf.y(),
176 right, bottom,
177 info.rectf.x(), bottom };
178 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
179 q->clip(vp, info.operation);
180 break;
181 }
182 }
183 }
184
185 if (transform != q->state()->matrix) {
186 q->state()->matrix = transform;
187 q->transformChanged();
188 }
189}
190
191
193{
194 Q_Q(const QPaintEngineEx);
195
196 QPainter *p = q->painter();
197 if (!p || !p->d_ptr)
198 return false;
199
200 return !p->d_ptr->state->clipInfo.isEmpty();
201}
202
203/*******************************************************************************
204 *
205 * class QPaintEngineEx:
206 *
207 */
208
227
246
280};
281
282
302
303
304
305static void qpaintengineex_moveTo(qreal x, qreal y, void *data) {
306 ((StrokeHandler *) data)->pts.add(x);
307 ((StrokeHandler *) data)->pts.add(y);
309}
310
311static void qpaintengineex_lineTo(qreal x, qreal y, void *data) {
312 ((StrokeHandler *) data)->pts.add(x);
313 ((StrokeHandler *) data)->pts.add(y);
315}
316
317static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data) {
318 ((StrokeHandler *) data)->pts.add(c1x);
319 ((StrokeHandler *) data)->pts.add(c1y);
321
322 ((StrokeHandler *) data)->pts.add(c2x);
323 ((StrokeHandler *) data)->pts.add(c2y);
325
326 ((StrokeHandler *) data)->pts.add(ex);
327 ((StrokeHandler *) data)->pts.add(ey);
329}
330
332 : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures)
333{
334 extended = true;
335}
336
342
344{
345 if (!orig)
346 return new QPainterState;
347 return new QPainterState(orig);
348}
349
350Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
351
352void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
353{
354#ifdef QT_DEBUG_DRAW
355 qDebug() << "QPaintEngineEx::stroke()" << inPen;
356#endif
357
358 Q_D(QPaintEngineEx);
359
360 if (path.isEmpty())
361 return;
362
363 if (!d->strokeHandler) {
364 d->strokeHandler = new StrokeHandler(path.elementCount()+4);
365 d->stroker.setMoveToHook(qpaintengineex_moveTo);
366 d->stroker.setLineToHook(qpaintengineex_lineTo);
367 d->stroker.setCubicToHook(qpaintengineex_cubicTo);
368 }
369
370 QRectF clipRect;
371 QPen pen = inPen;
372 if (pen.style() > Qt::SolidLine) {
373 QRectF cpRect = path.controlPointRect();
374 const QTransform &xf = state()->matrix;
375 if (pen.isCosmetic()) {
376 clipRect = d->exDeviceRect;
377 cpRect.translate(xf.dx(), xf.dy());
378 } else {
379 clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
380 }
381 // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
382 qreal pw = pen.widthF() ? pen.widthF() : 1;
383 QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
384 qreal extent = qMax(extentRect.width(), extentRect.height());
385 qreal patternLength = 0;
386 const QList<qreal> pattern = pen.dashPattern();
387 const int patternSize = qMin(pattern.size(), 32);
388 for (int i = 0; i < patternSize; i++)
389 patternLength += qMax(pattern.at(i), qreal(0));
390 patternLength *= pw;
391 if (qFuzzyIsNull(patternLength)) {
392 pen.setStyle(Qt::NoPen);
393 } else if (extent / patternLength > QDashStroker::repetitionLimit()) {
394 // approximate stream of tiny dashes with semi-transparent solid line
396 QColor color(pen.color());
397 color.setAlpha(color.alpha() / 2);
398 pen.setColor(color);
399 }
400 }
401
402 if (!qpen_fast_equals(pen, d->strokerPen)) {
403 d->strokerPen = pen;
404 d->stroker.setJoinStyle(pen.joinStyle());
405 d->stroker.setCapStyle(pen.capStyle());
406 d->stroker.setMiterLimit(pen.miterLimit());
407 qreal penWidth = pen.widthF();
408 if (penWidth == 0)
409 d->stroker.setStrokeWidth(1);
410 else
411 d->stroker.setStrokeWidth(penWidth);
412
413 Qt::PenStyle style = pen.style();
414 if (style == Qt::SolidLine) {
415 d->activeStroker = &d->stroker;
416 } else if (style == Qt::NoPen) {
417 d->activeStroker = nullptr;
418 } else {
419 d->dasher.setDashPattern(pen.dashPattern());
420 d->dasher.setDashOffset(pen.dashOffset());
421 d->activeStroker = &d->dasher;
422 }
423 }
424
425 if (!d->activeStroker) {
426 return;
427 }
428
429 if (!clipRect.isNull())
430 d->activeStroker->setClipRect(clipRect);
431
432 if (d->activeStroker == &d->stroker)
433 d->stroker.setForceOpen(path.hasExplicitOpen());
434
435 const QPainterPath::ElementType *types = path.elements();
436 const qreal *points = path.points();
437 int pointCount = path.elementCount();
438
439 const qreal *lastPoint = points + (pointCount<<1);
440
441 d->strokeHandler->types.reset();
442 d->strokeHandler->pts.reset();
443
444 // Some engines might decide to optimize for the non-shape hint later on...
446
447 if (path.elementCount() > 2)
449
450 if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin)
452
453 // ### Perspective Xforms are currently not supported...
454 if (!pen.isCosmetic()) {
455 // We include cosmetic pens in this case to avoid having to
456 // change the current transform. Normal transformed,
457 // non-cosmetic pens will be transformed as part of fill
458 // later, so they are also covered here..
459 d->activeStroker->setCurveThresholdFromTransform(state()->matrix);
460 d->activeStroker->begin(d->strokeHandler);
461 if (types) {
462 while (points < lastPoint) {
463 switch (*types) {
465 d->activeStroker->moveTo(points[0], points[1]);
466 points += 2;
467 ++types;
468 break;
470 d->activeStroker->lineTo(points[0], points[1]);
471 points += 2;
472 ++types;
473 break;
475 d->activeStroker->cubicTo(points[0], points[1],
476 points[2], points[3],
477 points[4], points[5]);
478 points += 6;
479 types += 3;
481 break;
482 default:
483 break;
484 }
485 }
486 if (path.hasImplicitClose())
487 d->activeStroker->lineTo(path.points()[0], path.points()[1]);
488
489 } else {
490 d->activeStroker->moveTo(points[0], points[1]);
491 points += 2;
492 while (points < lastPoint) {
493 d->activeStroker->lineTo(points[0], points[1]);
494 points += 2;
495 }
496 if (path.hasImplicitClose())
497 d->activeStroker->lineTo(path.points()[0], path.points()[1]);
498 }
499 d->activeStroker->end();
500
501 if (!d->strokeHandler->types.size()) // an empty path...
502 return;
503
504 QVectorPath strokePath(d->strokeHandler->pts.data(),
505 d->strokeHandler->types.size(),
506 d->strokeHandler->types.data(),
507 flags);
508 fill(strokePath, pen.brush());
509 } else {
510 // For cosmetic pens we need a bit of trickery... We to process xform the input points
511 if (state()->matrix.type() >= QTransform::TxProject) {
512 QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath());
513 d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform());
514 } else {
515 d->activeStroker->setCurveThresholdFromTransform(QTransform());
516 d->activeStroker->begin(d->strokeHandler);
517 if (types) {
518 while (points < lastPoint) {
519 switch (*types) {
521 QPointF pt = (*(const QPointF *) points) * state()->matrix;
522 d->activeStroker->moveTo(pt.x(), pt.y());
523 points += 2;
524 ++types;
525 break;
526 }
528 QPointF pt = (*(const QPointF *) points) * state()->matrix;
529 d->activeStroker->lineTo(pt.x(), pt.y());
530 points += 2;
531 ++types;
532 break;
533 }
535 QPointF c1 = ((const QPointF *) points)[0] * state()->matrix;
536 QPointF c2 = ((const QPointF *) points)[1] * state()->matrix;
537 QPointF e = ((const QPointF *) points)[2] * state()->matrix;
538 d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
539 points += 6;
540 types += 3;
542 break;
543 }
544 default:
545 break;
546 }
547 }
548 if (path.hasImplicitClose()) {
549 QPointF pt = * ((const QPointF *) path.points()) * state()->matrix;
550 d->activeStroker->lineTo(pt.x(), pt.y());
551 }
552
553 } else {
554 QPointF p = ((const QPointF *)points)[0] * state()->matrix;
555 d->activeStroker->moveTo(p.x(), p.y());
556 points += 2;
557 while (points < lastPoint) {
558 QPointF p = ((const QPointF *)points)[0] * state()->matrix;
559 d->activeStroker->lineTo(p.x(), p.y());
560 points += 2;
561 }
562 if (path.hasImplicitClose())
563 d->activeStroker->lineTo(p.x(), p.y());
564 }
565 d->activeStroker->end();
566 }
567
568 QVectorPath strokePath(d->strokeHandler->pts.data(),
569 d->strokeHandler->types.size(),
570 d->strokeHandler->types.data(),
571 flags);
572
574 state()->matrix = QTransform();
576
577 QBrush brush = pen.brush();
579 brush.setTransform(brush.transform() * xform);
580
581 fill(strokePath, brush);
582
583 state()->matrix = xform;
585 }
586}
587
589{
590 const QBrush &brush = state()->brush;
592 fill(path, brush);
593
594 const QPen &pen = state()->pen;
596 stroke(path, pen);
597}
598
599
601{
602 qreal right = r.x() + r.width();
603 qreal bottom = r.y() + r.height();
604 qreal pts[] = { qreal(r.x()), qreal(r.y()),
605 right, qreal(r.y()),
606 right, bottom,
607 qreal(r.x()), bottom,
608 qreal(r.x()), qreal(r.y()) };
609 QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
610 clip(vp, op);
611}
612
614{
615 const auto rectsInRegion = region.rectCount();
616 if (rectsInRegion == 1) {
617 clip(*region.begin(), op);
618 } else if (rectsInRegion <= 32) {
619 qreal pts[2*32*4];
620 int pos = 0;
621 for (QRect r : region) {
622 qreal x1 = r.x();
623 qreal y1 = r.y();
624 qreal x2 = r.x() + r.width();
625 qreal y2 = r.y() + r.height();
626
627 pts[pos++] = x1;
628 pts[pos++] = y1;
629
630 pts[pos++] = x2;
631 pts[pos++] = y1;
632
633 pts[pos++] = x2;
634 pts[pos++] = y2;
635
636 pts[pos++] = x1;
637 pts[pos++] = y2;
638 }
639 QVectorPath vp(pts, rectsInRegion * 4, qpaintengineex_rect4_types_32);
640 clip(vp, op);
641 } else {
642 QVarLengthArray<qreal> pts(rectsInRegion * 2 * 4);
643 QVarLengthArray<QPainterPath::ElementType> types(rectsInRegion * 4);
644 int ppos = 0;
645 int tpos = 0;
646
647 for (QRect r : region) {
648 qreal x1 = r.x();
649 qreal y1 = r.y();
650 qreal x2 = r.x() + r.width();
651 qreal y2 = r.y() + r.height();
652
653 pts[ppos++] = x1;
654 pts[ppos++] = y1;
655
656 pts[ppos++] = x2;
657 pts[ppos++] = y1;
658
659 pts[ppos++] = x2;
660 pts[ppos++] = y2;
661
662 pts[ppos++] = x1;
663 pts[ppos++] = y2;
664
669 }
670
671 QVectorPath vp(pts.data(), rectsInRegion * 4, types.data());
672 clip(vp, op);
673 }
674
675}
676
678{
679 if (path.isEmpty()) {
680 QVectorPath vp(nullptr, 0);
681 clip(vp, op);
682 } else {
684 }
685}
686
688{
689 qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(),
690 r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() };
691 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
692 fill(vp, brush);
693}
694
696{
698}
699
700void QPaintEngineEx::drawRects(const QRect *rects, int rectCount)
701{
702 for (int i=0; i<rectCount; ++i) {
703 const QRect &r = rects[i];
704 // ### Is there a one off here?
705 qreal right = r.x() + r.width();
706 qreal bottom = r.y() + r.height();
707 qreal pts[] = { qreal(r.x()), qreal(r.y()),
708 right, qreal(r.y()),
709 right, bottom,
710 qreal(r.x()), bottom,
711 qreal(r.x()), qreal(r.y()) };
712 QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
713 draw(vp);
714 }
715}
716
717void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount)
718{
719 for (int i=0; i<rectCount; ++i) {
720 const QRectF &r = rects[i];
721 qreal right = r.x() + r.width();
722 qreal bottom = r.y() + r.height();
723 qreal pts[] = { r.x(), r.y(),
724 right, r.y(),
725 right, bottom,
726 r.x(), bottom,
727 r.x(), r.y() };
728 QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
729 draw(vp);
730 }
731}
732
733
736{
737 qreal x1 = rect.left();
738 qreal x2 = rect.right();
739 qreal y1 = rect.top();
740 qreal y2 = rect.bottom();
741
742 if (mode == Qt::RelativeSize) {
743 xRadius = xRadius * rect.width() / 200.;
744 yRadius = yRadius * rect.height() / 200.;
745 }
746
747 xRadius = qMin(xRadius, rect.width() / 2);
748 yRadius = qMin(yRadius, rect.height() / 2);
749
750 qreal pts[] = {
751 x1 + xRadius, y1, // MoveTo
752 x2 - xRadius, y1, // LineTo
753 x2 - (1 - KAPPA) * xRadius, y1, // CurveTo
754 x2, y1 + (1 - KAPPA) * yRadius,
755 x2, y1 + yRadius,
756 x2, y2 - yRadius, // LineTo
757 x2, y2 - (1 - KAPPA) * yRadius, // CurveTo
758 x2 - (1 - KAPPA) * xRadius, y2,
759 x2 - xRadius, y2,
760 x1 + xRadius, y2, // LineTo
761 x1 + (1 - KAPPA) * xRadius, y2, // CurveTo
762 x1, y2 - (1 - KAPPA) * yRadius,
763 x1, y2 - yRadius,
764 x1, y1 + yRadius, // LineTo
765 x1, y1 + (1 - KAPPA) * yRadius, // CurveTo
766 x1 + (1 - KAPPA) * xRadius, y1,
767 x1 + xRadius, y1
768 };
769
771 draw(path);
772}
773
774
775
776void QPaintEngineEx::drawLines(const QLine *lines, int lineCount)
777{
778 int elementCount = lineCount << 1;
779 while (elementCount > 0) {
780 int count = qMin(elementCount, 32);
781
782 qreal pts[64];
783 int count2 = count<<1;
784 for (int i=0; i<count2; ++i)
785 pts[i] = ((const int *) lines)[i];
786
788 stroke(path, state()->pen);
789
790 elementCount -= 32;
791 lines += 16;
792 }
793}
794
795void QPaintEngineEx::drawLines(const QLineF *lines, int lineCount)
796{
797 int elementCount = lineCount << 1;
798 while (elementCount > 0) {
799 int count = qMin(elementCount, 32);
800
803 stroke(path, state()->pen);
804
805 elementCount -= 32;
806 lines += 16;
807 }
808}
809
811{
812 qreal pts[26]; // QPointF[13] without constructors...
813 union {
814 qreal *ptr;
816 } x;
817 x.ptr = pts;
818
819 int point_count = 0;
820 x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
821 if (point_count == 0)
822 return;
824 draw(vp);
825}
826
831
833{
834 if (!path.isEmpty())
836}
837
838
839void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
840{
841 QPen pen = state()->pen;
842 if (pen.capStyle() == Qt::FlatCap)
844
845 if (pen.brush().isOpaque()) {
846 while (pointCount > 0) {
847 int count = qMin(pointCount, 16);
848 qreal pts[64];
849 int oset = -1;
850 for (int i=0; i<count; ++i) {
851 pts[++oset] = points[i].x();
852 pts[++oset] = points[i].y();
853 pts[++oset] = points[i].x() + 1/63.;
854 pts[++oset] = points[i].y();
855 }
857 stroke(path, pen);
858 pointCount -= 16;
859 points += 16;
860 }
861 } else {
862 for (int i=0; i<pointCount; ++i) {
863 qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + qreal(1/63.), points[i].y() };
864 QVectorPath path(pts, 2, nullptr);
865 stroke(path, pen);
866 }
867 }
868}
869
870void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
871{
872 QPen pen = state()->pen;
873 if (pen.capStyle() == Qt::FlatCap)
875
876 if (pen.brush().isOpaque()) {
877 while (pointCount > 0) {
878 int count = qMin(pointCount, 16);
879 qreal pts[64];
880 int oset = -1;
881 for (int i=0; i<count; ++i) {
882 pts[++oset] = points[i].x();
883 pts[++oset] = points[i].y();
884 pts[++oset] = points[i].x() + 1/63.;
885 pts[++oset] = points[i].y();
886 }
888 stroke(path, pen);
889 pointCount -= 16;
890 points += 16;
891 }
892 } else {
893 for (int i=0; i<pointCount; ++i) {
894 qreal pts[] = { qreal(points[i].x()), qreal(points[i].y()),
895 qreal(points[i].x() +1/63.), qreal(points[i].y()) };
896 QVectorPath path(pts, 2, nullptr);
897 stroke(path, pen);
898 }
899 }
900}
901
902
904{
905 Q_ASSERT(pointCount >= 2);
906 QVectorPath path((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
907
908 if (mode == PolylineMode)
909 stroke(path, state()->pen);
910 else
911 draw(path);
912}
913
915{
916 Q_ASSERT(pointCount >= 2);
917 int count = pointCount<<1;
918 QVarLengthArray<qreal> pts(count);
919
920 for (int i=0; i<count; ++i)
921 pts[i] = ((const int *) points)[i];
922
923 QVectorPath path(pts.data(), pointCount, nullptr, QVectorPath::polygonFlags(mode));
924
925 if (mode == PolylineMode)
926 stroke(path, state()->pen);
927 else
928 draw(path);
929
930}
931
933{
935}
936
938{
939 drawImage(QRectF(pos, image.deviceIndependentSize()), image, image.rect());
940}
941
943{
944 QBrush brush(state()->pen.color(), pixmap);
945 QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
946 if (!qFuzzyCompare(pixmap.devicePixelRatio(), qreal(1.0)))
947 xform.scale(1.0/pixmap.devicePixelRatio(), 1.0/pixmap.devicePixelRatio());
948 brush.setTransform(xform);
949
950 qreal pts[] = { r.x(), r.y(),
951 r.x() + r.width(), r.y(),
952 r.x() + r.width(), r.y() + r.height(),
953 r.x(), r.y() + r.height() };
954
956 fill(path, brush);
957}
958
959void QPaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount,
960 const QPixmap &pixmap, QPainter::PixmapFragmentHints /*hints*/)
961{
962 if (pixmap.isNull())
963 return;
964
965 qreal oldOpacity = state()->opacity;
966 QTransform oldTransform = state()->matrix;
967
968 for (int i = 0; i < fragmentCount; ++i) {
969 QTransform transform = oldTransform;
970 transform.translate(fragments[i].x, fragments[i].y);
971 transform.rotate(fragments[i].rotation);
972 state()->opacity = oldOpacity * fragments[i].opacity;
976
977 qreal w = fragments[i].scaleX * fragments[i].width;
978 qreal h = fragments[i].scaleY * fragments[i].height;
979 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
980 fragments[i].width, fragments[i].height);
981 drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect);
982 }
983
984 state()->opacity = oldOpacity;
985 state()->matrix = oldTransform;
988}
989
994
995
997{
998 // do nothing...
999}
1000
1002{
1003 const qreal *points = path.points();
1004 const QPainterPath::ElementType *types = path.elements();
1005
1007 if (types) {
1008 int id = 0;
1009 for (int i=0; i<path.elementCount(); ++i) {
1010 switch(types[i]) {
1012 p.moveTo(QPointF(points[id], points[id+1]));
1013 id+=2;
1014 break;
1016 p.lineTo(QPointF(points[id], points[id+1]));
1017 id+=2;
1018 break;
1020 QPointF p1(points[id], points[id+1]);
1021 QPointF p2(points[id+2], points[id+3]);
1022 QPointF p3(points[id+4], points[id+5]);
1023 p.cubicTo(p1, p2, p3);
1024 id+=6;
1025 break;
1026 }
1028 ;
1029 break;
1030 }
1031 }
1032 } else {
1033 p.moveTo(QPointF(points[0], points[1]));
1034 int id = 2;
1035 for (int i=1; i<path.elementCount(); ++i) {
1036 p.lineTo(QPointF(points[id], points[id+1]));
1037 id+=2;
1038 }
1039 }
1040 if (path.hints() & QVectorPath::WindingFill)
1041 p.setFillRule(Qt::WindingFill);
1042
1043 return p;
1044}
1045
1047{
1049 path.setFillRule(Qt::WindingFill);
1050
1051 if (staticTextItem->numGlyphs == 0)
1052 return;
1053
1054 QFontEngine *fontEngine = staticTextItem->fontEngine();
1055 fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
1056 staticTextItem->numGlyphs, &path, { });
1057 if (!path.isEmpty()) {
1058 QPainterState *s = state();
1059 QPainter::RenderHints oldHints = s->renderHints;
1060 bool changedHints = false;
1061 if (bool(oldHints & QPainter::TextAntialiasing)
1062 && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
1063 && !bool(oldHints & QPainter::Antialiasing)) {
1064 s->renderHints |= QPainter::Antialiasing;
1066 changedHints = true;
1067 }
1068
1069 fill(qtVectorPathForPath(path), s->pen.brush());
1070
1071 if (changedHints) {
1072 s->renderHints = oldHints;
1074 }
1075 }
1076}
1077
1079{
1080 return false;
1081}
1082
1084{
1085 if (fontEngine->glyphFormat == QFontEngine::Format_ARGB)
1086 return true;
1087
1088 static const int maxCachedGlyphSizeSquared = std::pow([]{
1089 if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE"))
1090 return env;
1092 }(), 2);
1093
1094 qreal pixelSize = fontEngine->fontDef.pixelSize;
1095 return (pixelSize * pixelSize * qAbs(m.determinant())) <= maxCachedGlyphSizeSquared;
1096}
1097
\inmodule QtGui
Definition qbrush.h:30
bool isOpaque() const
Returns true if the brush is fully opaque otherwise false.
Definition qbrush.cpp:830
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static int repetitionLimit()
Definition qstroker_p.h:235
\inmodule QtCore
\inmodule QtCore
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags)
QFontDef fontDef
GlyphFormat glyphFormat
@ NoAntialias
Definition qfont.h:47
\inmodule QtGui
Definition qimage.h:37
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
\inmodule QtCore\compares equality \compareswith equality QLineF \endcompareswith
Definition qline.h:18
StrokeHandler * strokeHandler
virtual void drawRects(const QRect *rects, int rectCount) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
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
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
virtual void drawEllipse(const QRectF &r) override
Reimplement this function to draw the largest ellipse that can be contained within rectangle rect.
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags=Qt::AutoColor) override=0
Reimplement this function to draw the part of the image specified by the sr rectangle in the given re...
virtual void drawLines(const QLine *lines, int lineCount) override
This is an overloaded member function, provided for convenience. It differs from the above function o...
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
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r.
QPainterState * state()
virtual QPainterState * createState(QPainterState *orig) const
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override
Reimplement this function to draw the pixmap in the given rect, starting at the given p.
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
Reimplement this function to update the state of a paint engine.
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
Draws the first pointCount points in the buffer points.
virtual void drawPath(const QPainterPath &path) override
The default implementation ignores the path and does nothing.
virtual void drawStaticTextItem(QStaticTextItem *)
The QPaintEngineState class provides information about the active paint engine's current state....
\inmodule QtGui
PolygonDrawMode
\value OddEvenMode The polygon should be drawn using OddEven fill rule.
QPaintEngineState * state
\inmodule QtGui
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
QTransform matrix
Definition qpainter_p.h:130
This class is used in conjunction with the QPainter::drawPixmapFragments() function to specify how a ...
Definition qpainter.h:64
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ Antialiasing
Definition qpainter.h:52
@ TextAntialiasing
Definition qpainter.h:53
\inmodule QtGui
Definition qpen.h:28
void setCapStyle(Qt::PenCapStyle pcs)
Sets the pen's cap style to the given style.
Definition qpen.cpp:650
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:572
void setStyle(Qt::PenStyle)
[0]
QList< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition qpen.cpp:400
bool isCosmetic() const
Returns true if the pen is cosmetic; otherwise returns false.
Definition qpen.cpp:757
QColor color() const
Returns the color of this pen's brush.
Definition qpen.cpp:692
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
void setColor(const QColor &color)
Sets the color of this pen's brush to the given color.
Definition qpen.cpp:705
void setJoinStyle(Qt::PenJoinStyle pcs)
Sets the pen's join style to the given style.
Definition qpen.cpp:677
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:663
qreal miterLimit() const
Returns the miter limit of the pen.
Definition qpen.cpp:524
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition qpen.cpp:715
qreal dashOffset() const
Returns the dash offset for the pen.
Definition qpen.cpp:484
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QSizeF deviceIndependentSize() const
Returns the size of the pixmap in device independent pixels.
Definition qpixmap.cpp:626
QRect rect() const
Returns the pixmap's enclosing rectangle.
Definition qpixmap.cpp:505
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:658
constexpr void translate(qreal dx, qreal dy) noexcept
Moves the rectangle dx along the x-axis and dy along the y-axis, relative to the current position.
Definition qrect.h:738
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
int rectCount() const noexcept
const_iterator begin() const noexcept
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
QPoint map(const QPoint &p) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis.
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
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
QPixmap p2
QPixmap p1
[0]
set reserve(20000)
rect
[4]
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ RelativeSize
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
ClipOperation
@ SolidLine
@ NoPen
@ RoundJoin
@ SolidPattern
@ NoBrush
@ WindingFill
@ SquareCap
@ RoundCap
@ FlatCap
Definition brush.cpp:5
Definition image.cpp:4
#define KAPPA
Definition qbezier.cpp:292
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define qDebug
[1]
Definition qlogging.h:164
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLboolean r
[2]
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLuint color
[2]
GLint GLint bottom
GLbitfield flags
GLfloat n
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLfixed GLfixed GLint GLint GLfixed points
GLdouble s
[6]
Definition qopenglext.h:235
GLfixed GLfixed GLfixed y2
GLuint GLenum matrix
GLfixed GLfixed x2
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
GLenum GLenum GLenum GLenum GLenum scale
GLubyte * pattern
static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data)
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
static const QPainterPath::ElementType qpaintengineex_roundedrect_types[]
static const QPainterPath::ElementType qpaintengineex_rect4_types_32[]
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
static const QPainterPath::ElementType qpaintengineex_line_types_16[]
static void qpaintengineex_lineTo(qreal x, qreal y, void *data)
#define QT_MAX_CACHED_GLYPH_SIZE
Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
static void qpaintengineex_moveTo(qreal x, qreal y, void *data)
static const QPainterPath::ElementType qpaintengineex_ellipse_types[]
Qt::BrushStyle qbrush_style(const QBrush &b)
Definition qpainter_p.h:63
bool qpen_fast_equals(const QPen &a, const QPen &b)
Definition qpainter_p.h:53
Qt::PenStyle qpen_style(const QPen &p)
Definition qpainter_p.h:56
QBrush qpen_brush(const QPen &p)
Definition qpainter_p.h:54
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition qstroker.cpp:816
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
void(* qvectorpath_cache_cleanup)(QPaintEngineEx *engine, void *data)
QObject::connect nullptr
MyCustomStruct c2
widget render & pixmap
QHostInfo info
[0]
QJSEngine engine
[0]
uint styleStrategy
Definition qfont_p.h:64
qreal pixelSize
Definition qfont_p.h:61
QPaintEngineEx * engine
qvectorpath_cache_cleanup cleanup
QDataBuffer< qreal > pts
StrokeHandler(int reserve)
QDataBuffer< QPainterPath::ElementType > types