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#include "qpaintengine.h"
4#include "qpaintengine_p.h"
5#include "qpainter_p.h"
6#include "qpolygon.h"
7#include "qbitmap.h"
8#include <qdebug.h>
9#include <qmath.h>
10#include <qguiapplication.h>
11#include <qvarlengtharray.h>
12#include <qpa/qplatformintegration.h>
13#include <qpa/qplatformpixmap.h>
14#include <private/qfontengine_p.h>
15#include <private/qguiapplication_p.h>
16#include <private/qpaintengineex_p.h>
17#include <private/qtextengine_p.h>
18
19#include <memory>
20
21QT_BEGIN_NAMESPACE
22
23/*!
24 \class QTextItem
25 \inmodule QtGui
26
27 \brief The QTextItem class provides all the information required to draw
28 text in a custom paint engine.
29
30 When you reimplement your own paint engine, you must reimplement
31 QPaintEngine::drawTextItem(), a function that takes a QTextItem as
32 one of its arguments.
33*/
34
35/*!
36 \enum QTextItem::RenderFlag
37
38 \value RightToLeft Render the text from right to left.
39 \value Overline Paint a line above the text.
40 \value Underline Paint a line under the text.
41 \value StrikeOut Paint a line through the text.
42 \omitvalue Dummy
43*/
44
45
46/*!
47 \fn qreal QTextItem::descent() const
48
49 Corresponds to the \l{QFontMetrics::descent()}{descent} of the piece of text that is drawn.
50*/
51qreal QTextItem::descent() const
52{
53 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
54 return ti->descent.toReal();
55}
56
57/*!
58 \fn qreal QTextItem::ascent() const
59
60 Corresponds to the \l{QFontMetrics::ascent()}{ascent} of the piece of text that is drawn.
61*/
62qreal QTextItem::ascent() const
63{
64 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
65 return ti->ascent.toReal();
66}
67
68/*!
69 \fn qreal QTextItem::width() const
70
71 Specifies the total width of the text to be drawn.
72*/
73qreal QTextItem::width() const
74{
75 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
76 return ti->width.toReal();
77}
78
79/*!
80 \fn QTextItem::RenderFlags QTextItem::renderFlags() const
81
82 Returns the render flags used.
83*/
84QTextItem::RenderFlags QTextItem::renderFlags() const
85{
86 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
87 return ti->flags;
88}
89
90/*!
91 \fn QString QTextItem::text() const
92
93 Returns the text that should be drawn.
94*/
95QString QTextItem::text() const
96{
97 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
98 return QString(ti->chars, ti->num_chars);
99}
100
101/*!
102 \fn QFont QTextItem::font() const
103
104 Returns the font that should be used to draw the text.
105*/
106QFont QTextItem::font() const
107{
108 const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
109 return ti->f ? *ti->f : QGuiApplication::font();
110}
111
112
113/*!
114 \class QPaintEngine
115 \ingroup painting
116 \inmodule QtGui
117
118 \brief The QPaintEngine class provides an abstract definition of how
119 QPainter draws to a given device on a given platform.
120
121 Qt provides several premade implementations of QPaintEngine for the
122 different painter backends we support. The primary paint engine
123 provided is the raster paint engine, which contains a software
124 rasterizer which supports the full feature set on all supported platforms.
125 This is the default for painting on QWidget-based classes in e.g. on Windows,
126 X11 and \macos, it is the backend for painting on QImage and it is
127 used as a fallback for paint engines that do not support a certain
128 capability. In addition we provide QPaintEngine implementations for
129 OpenGL (accessible through QOpenGLWidget) and printing (which allows using
130 QPainter to draw on a QPrinter object).
131
132 If one wants to use QPainter to draw to a different backend,
133 one must subclass QPaintEngine and reimplement all its virtual
134 functions. The QPaintEngine implementation is then made available by
135 subclassing QPaintDevice and reimplementing the virtual function
136 QPaintDevice::paintEngine().
137
138 QPaintEngine is created and owned by the QPaintDevice that created it.
139
140 \sa QPainter, QPaintDevice::paintEngine(), {Paint System}
141*/
142
143/*!
144 \enum QPaintEngine::PaintEngineFeature
145
146 This enum is used to describe the features or capabilities that the
147 paint engine has. If a feature is not supported by the engine,
148 QPainter will do a best effort to emulate that feature through other
149 means and pass on an alpha blended QImage to the engine with the
150 emulated results. Some features cannot be emulated: AlphaBlend and PorterDuff.
151
152 \value AlphaBlend The engine can alpha blend primitives.
153 \value Antialiasing The engine can use antialiasing to improve the appearance
154 of rendered primitives.
155 \value BlendModes The engine supports blending modes.
156 \value BrushStroke The engine supports drawing strokes that
157 contain brushes as fills, not just solid
158 colors (e.g. a dashed gradient line of
159 width 2).
160 \value ConicalGradientFill The engine supports conical gradient fills.
161 \value ConstantOpacity The engine supports the feature provided by
162 QPainter::setOpacity().
163 \value LinearGradientFill The engine supports linear gradient fills.
164 \value MaskedBrush The engine is capable of rendering brushes that has a
165 texture with an alpha channel or a mask.
166 \value ObjectBoundingModeGradients The engine has native support for gradients
167 with coordinate mode QGradient::ObjectBoundingMode.
168 Otherwise, if QPaintEngine::PatternTransform is
169 supported, object bounding mode gradients are
170 converted to gradients with coordinate mode
171 QGradient::LogicalMode and a brush transform for
172 the coordinate mapping.
173 \value PainterPaths The engine has path support.
174 \value PaintOutsidePaintEvent The engine is capable of painting outside of
175 paint events.
176 \value PatternBrush The engine is capable of rendering brushes with
177 the brush patterns specified in Qt::BrushStyle.
178 \value PatternTransform The engine has support for transforming brush
179 patterns.
180 \value PerspectiveTransform The engine has support for performing perspective
181 transformations on primitives.
182 \value PixmapTransform The engine can transform pixmaps, including
183 rotation and shearing.
184 \value PorterDuff The engine supports Porter-Duff operations
185 \value PrimitiveTransform The engine has support for transforming
186 drawing primitives.
187 \value RadialGradientFill The engine supports radial gradient fills.
188 \value RasterOpModes The engine supports bitwise raster operations.
189 \value AllFeatures All of the above features. This enum value is usually
190 used as a bit mask.
191*/
192
193/*!
194 \enum QPaintEngine::PolygonDrawMode
195
196 \value OddEvenMode The polygon should be drawn using OddEven fill
197 rule.
198
199 \value WindingMode The polygon should be drawn using Winding fill rule.
200
201 \value ConvexMode The polygon is a convex polygon and can be drawn
202 using specialized algorithms where available.
203
204 \value PolylineMode Only the outline of the polygon should be
205 drawn.
206
207*/
208
209/*!
210 \enum QPaintEngine::DirtyFlag
211
212 \value DirtyPen The pen is dirty and needs to be updated.
213
214 \value DirtyBrush The brush is dirty and needs to be updated.
215
216 \value DirtyBrushOrigin The brush origin is dirty and needs to
217 updated.
218
219 \value DirtyFont The font is dirty and needs to be updated.
220
221 \value DirtyBackground The background is dirty and needs to be
222 updated.
223
224 \value DirtyBackgroundMode The background mode is dirty and needs
225 to be updated.
226
227 \value DirtyTransform The transform is dirty and needs to be
228 updated.
229
230 \value DirtyClipRegion The clip region is dirty and needs to be
231 updated.
232
233 \value DirtyClipPath The clip path is dirty and needs to be
234 updated.
235
236 \value DirtyHints The render hints is dirty and needs to be
237 updated.
238
239 \value DirtyCompositionMode The composition mode is dirty and
240 needs to be updated.
241
242 \value DirtyClipEnabled Whether clipping is enabled or not is
243 dirty and needs to be updated.
244
245 \value DirtyOpacity The constant opacity has changed and needs to
246 be updated as part of the state change in
247 QPaintEngine::updateState().
248
249 \value AllDirty Convenience enum used internally.
250
251 These types are used by QPainter to trigger lazy updates of the
252 various states in the QPaintEngine using
253 QPaintEngine::updateState().
254
255 A paint engine must update every dirty state.
256*/
257
258/*!
259 \fn void QPaintEngine::syncState()
260
261 \internal
262
263 Updates all dirty states in this engine. This function should ONLY
264 be used when drawing with native handles directly and immediate sync
265 from QPainters state to the native state is required.
266*/
267void QPaintEngine::syncState()
268{
269 Q_ASSERT(state);
270 updateState(state: *state);
271
272 if (isExtended())
273 static_cast<QPaintEngineEx *>(this)->sync();
274}
275
276static QPaintEngine *qt_polygon_recursion = nullptr;
277struct QT_Point {
278 int x;
279 int y;
280};
281Q_DECLARE_TYPEINFO(QT_Point, Q_PRIMITIVE_TYPE);
282
283/*!
284 \fn void QPaintEngine::drawPolygon(const QPointF *points, int pointCount,
285 PolygonDrawMode mode)
286
287 Reimplement this virtual function to draw the polygon defined
288 by the \a pointCount first points in \a points, using mode \a
289 mode.
290
291 \note At least one of the drawPolygon() functions must be reimplemented.
292*/
293void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
294{
295 Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
296 "At least one drawPolygon function must be implemented");
297 qt_polygon_recursion = this;
298 Q_ASSERT(sizeof(QT_Point) == sizeof(QPoint));
299 QVarLengthArray<QT_Point> p(pointCount);
300 for (int i = 0; i < pointCount; ++i) {
301 p[i].x = qRound(d: points[i].x());
302 p[i].y = qRound(d: points[i].y());
303 }
304 drawPolygon(points: (QPoint *)p.data(), pointCount, mode);
305 qt_polygon_recursion = nullptr;
306}
307
308struct QT_PointF {
309 qreal x;
310 qreal y;
311};
312Q_DECLARE_TYPEINFO(QT_PointF, Q_PRIMITIVE_TYPE);
313
314/*!
315 \overload
316
317 Reimplement this virtual function to draw the polygon defined by the
318 \a pointCount first points in \a points, using mode \a mode.
319
320 \note At least one of the drawPolygon() functions must be reimplemented.
321*/
322void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
323{
324 Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
325 "At least one drawPolygon function must be implemented");
326 qt_polygon_recursion = this;
327 Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
328 QVarLengthArray<QT_PointF> p(pointCount);
329 for (int i=0; i<pointCount; ++i) {
330 p[i].x = points[i].x();
331 p[i].y = points[i].y();
332 }
333 drawPolygon(points: (QPointF *)p.data(), pointCount, mode);
334 qt_polygon_recursion = nullptr;
335}
336
337/*!
338 \enum QPaintEngine::Type
339
340 \value X11
341 \value Windows
342 \value MacPrinter
343 \value CoreGraphics \macos's Quartz2D (CoreGraphics)
344 \value QuickDraw \macos's QuickDraw
345 \value QWindowSystem Qt for Embedded Linux
346 \value OpenGL
347 \value Picture QPicture format
348 \value SVG Scalable Vector Graphics XML format
349 \value Raster
350 \value Direct3D Windows only, Direct3D based engine
351 \value Pdf Portable Document Format
352 \value OpenVG
353 \value User First user type ID
354 \value MaxUser Last user type ID
355 \value OpenGL2
356 \value PaintBuffer
357 \value Blitter
358 \value Direct2D Windows only, Direct2D based engine
359*/
360
361/*!
362 \fn bool QPaintEngine::isActive() const
363
364 Returns \c true if the paint engine is actively drawing; otherwise
365 returns \c false.
366
367 \sa setActive()
368*/
369
370/*!
371 \fn void QPaintEngine::setActive(bool state)
372
373 Sets the active state of the paint engine to \a state.
374
375 \sa isActive()
376*/
377
378/*!
379 \fn bool QPaintEngine::begin(QPaintDevice *pdev)
380
381 Reimplement this function to initialise your paint engine when
382 painting is to start on the paint device \a pdev. Return true if
383 the initialization was successful; otherwise return false.
384
385 \sa end(), isActive()
386*/
387
388/*!
389 \fn bool QPaintEngine::end()
390
391 Reimplement this function to finish painting on the current paint
392 device. Return true if painting was finished successfully;
393 otherwise return false.
394
395 \sa begin(), isActive()
396*/
397
398
399/*!
400 Draws the first \a pointCount points in the buffer \a points
401*/
402void QPaintEngine::drawPoints(const QPointF *points, int pointCount)
403{
404 QPainter *p = painter();
405 if (!p)
406 return;
407
408 qreal penWidth = p->pen().widthF();
409 if (penWidth == 0)
410 penWidth = 1;
411
412 bool ellipses = p->pen().capStyle() == Qt::RoundCap;
413
414 p->save();
415
416 QTransform transform;
417 if (p->pen().isCosmetic()) {
418 transform = p->transform();
419 p->setTransform(transform: QTransform());
420 }
421
422 p->setBrush(p->pen().brush());
423 p->setPen(Qt::NoPen);
424
425 for (int i=0; i<pointCount; ++i) {
426 QPointF pos = transform.map(p: points[i]);
427 QRectF rect(pos.x() - penWidth / 2, pos.y() - penWidth / 2, penWidth, penWidth);
428
429 if (ellipses)
430 p->drawEllipse(r: rect);
431 else
432 p->drawRect(rect);
433 }
434
435 p->restore();
436}
437
438
439/*!
440 Draws the first \a pointCount points in the buffer \a points
441
442 The default implementation converts the first \a pointCount QPoints in \a points
443 to QPointFs and calls the floating point version of drawPoints.
444
445*/
446void QPaintEngine::drawPoints(const QPoint *points, int pointCount)
447{
448 Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
449 QT_PointF fp[256];
450 while (pointCount) {
451 int i = 0;
452 while (i < pointCount && i < 256) {
453 fp[i].x = points[i].x();
454 fp[i].y = points[i].y();
455 ++i;
456 }
457 drawPoints(points: (QPointF *)(void *)fp, pointCount: i);
458 points += i;
459 pointCount -= i;
460 }
461}
462
463/*!
464 \fn void QPaintEngine::drawEllipse(const QRectF &rect)
465
466 Reimplement this function to draw the largest ellipse that can be
467 contained within rectangle \a rect.
468
469 The default implementation calls drawPolygon().
470*/
471void QPaintEngine::drawEllipse(const QRectF &rect)
472{
473 QPainterPath path;
474 path.addEllipse(rect);
475 if (hasFeature(feature: PainterPaths)) {
476 drawPath(path);
477 } else {
478 QPolygonF polygon = path.toFillPolygon();
479 drawPolygon(points: polygon.data(), pointCount: polygon.size(), mode: ConvexMode);
480 }
481}
482
483/*!
484 The default implementation of this function calls the floating
485 point version of this function
486*/
487void QPaintEngine::drawEllipse(const QRect &rect)
488{
489 drawEllipse(rect: QRectF(rect));
490}
491
492/*!
493 \fn void QPaintEngine::drawPixmap(const QRectF &r, const QPixmap
494 &pm, const QRectF &sr)
495
496 Reimplement this function to draw the part of the \a pm
497 specified by the \a sr rectangle in the given \a r.
498*/
499
500
501void qt_fill_tile(QPixmap *tile, const QPixmap &pixmap)
502{
503 QPainter p(tile);
504 p.drawPixmap(x: 0, y: 0, pm: pixmap);
505 int x = pixmap.width();
506 while (x < tile->width()) {
507 p.drawPixmap(x, y: 0, pm: *tile, sx: 0, sy: 0, sw: x, sh: pixmap.height());
508 x *= 2;
509 }
510 int y = pixmap.height();
511 while (y < tile->height()) {
512 p.drawPixmap(x: 0, y, pm: *tile, sx: 0, sy: 0, sw: tile->width(), sh: y);
513 y *= 2;
514 }
515}
516
517Q_GUI_EXPORT void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
518 const QPixmap &pixmap, qreal xOffset, qreal yOffset)
519{
520 qreal yPos, xPos, drawH, drawW, yOff, xOff;
521 yPos = y;
522 yOff = yOffset;
523 while(yPos < y + h) {
524 drawH = pixmap.height() - yOff; // Cropping first row
525 if (yPos + drawH > y + h) // Cropping last row
526 drawH = y + h - yPos;
527 xPos = x;
528 xOff = xOffset;
529 while(xPos < x + w) {
530 drawW = pixmap.width() - xOff; // Cropping first column
531 if (xPos + drawW > x + w) // Cropping last column
532 drawW = x + w - xPos;
533 if (drawW > 0 && drawH > 0)
534 gc->drawPixmap(r: QRectF(xPos, yPos, drawW, drawH), pm: pixmap, sr: QRectF(xOff, yOff, drawW, drawH));
535 xPos += drawW;
536 xOff = 0;
537 }
538 yPos += drawH;
539 yOff = 0;
540 }
541}
542
543
544/*!
545 Reimplement this function to draw the \a pixmap in the given \a
546 rect, starting at the given \a p. The pixmap will be
547 drawn repeatedly until the \a rect is filled.
548*/
549void QPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p)
550{
551 int sw = pixmap.width();
552 int sh = pixmap.height();
553
554 if (sw*sh < 8192 && sw*sh < 16*rect.width()*rect.height()) {
555 int tw = sw, th = sh;
556 while (tw*th < 32678 && tw < rect.width()/2)
557 tw *= 2;
558 while (tw*th < 32678 && th < rect.height()/2)
559 th *= 2;
560 QPixmap tile;
561 if (pixmap.depth() == 1) {
562 tile = QBitmap(tw, th);
563 } else {
564 tile = QPixmap(tw, th);
565 if (pixmap.hasAlphaChannel())
566 tile.fill(fillColor: Qt::transparent);
567 }
568 qt_fill_tile(tile: &tile, pixmap);
569 qt_draw_tile(gc: this, x: rect.x(), y: rect.y(), w: rect.width(), h: rect.height(), pixmap: tile, xOffset: p.x(), yOffset: p.y());
570 } else {
571 qt_draw_tile(gc: this, x: rect.x(), y: rect.y(), w: rect.width(), h: rect.height(), pixmap, xOffset: p.x(), yOffset: p.y());
572 }
573}
574
575/*!
576 \fn void QPaintEngine::drawImage(const QRectF &rectangle, const QImage
577 &image, const QRectF &sr, Qt::ImageConversionFlags flags)
578
579 Reimplement this function to draw the part of the \a image
580 specified by the \a sr rectangle in the given \a rectangle using
581 the given conversion flags \a flags, to convert it to a pixmap.
582*/
583
584void QPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
585 Qt::ImageConversionFlags flags)
586{
587 QRectF baseSize(0, 0, image.width(), image.height());
588 QImage im = image;
589 if (baseSize != sr)
590 im = im.copy(x: qFloor(v: sr.x()), y: qFloor(v: sr.y()),
591 w: qCeil(v: sr.width()), h: qCeil(v: sr.height()));
592 QPixmap pm = QPixmap::fromImage(image: im, flags);
593 drawPixmap(r, pm, sr: QRectF(QPointF(0, 0), pm.size()));
594}
595
596/*!
597 \fn Type QPaintEngine::type() const
598
599 Reimplement this function to return the paint engine \l{Type}.
600*/
601
602/*!
603 \fn void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h);
604
605 \internal
606*/
607
608/*!
609 \fn bool QPaintEngine::testDirty(DirtyFlags df)
610
611 \internal
612*/
613
614/*!
615 \fn void QPaintEngine::clearDirty(DirtyFlags df)
616
617 \internal
618*/
619
620/*!
621 \fn void QPaintEngine::setDirty(DirtyFlags df)
622
623 \internal
624*/
625
626/*!
627 \fn bool QPaintEngine::hasFeature(PaintEngineFeatures feature) const
628
629 Returns \c true if the paint engine supports the specified \a
630 feature; otherwise returns \c false.
631*/
632
633/*!
634 \fn bool QPaintEngine::isExtended() const
635
636 \internal
637
638 Returns \c true if the paint engine is a QPaintEngineEx derivative.
639*/
640
641/*!
642 \fn void QPaintEngine::updateState(const QPaintEngineState &state)
643
644 Reimplement this function to update the state of a paint engine.
645
646 When implemented, this function is responsible for checking the
647 paint engine's current \a state and update the properties that are
648 changed. Use the QPaintEngineState::state() function to find out
649 which properties that must be updated, then use the corresponding
650 \l {GetFunction}{get function} to retrieve the current values for
651 the given properties.
652
653 \sa QPaintEngineState
654*/
655
656/*!
657 Creates a paint engine with the featureset specified by \a caps.
658*/
659
660QPaintEngine::QPaintEngine(PaintEngineFeatures caps)
661 : state(nullptr),
662 gccaps(caps),
663 active(0),
664 selfDestruct(false),
665 extended(false),
666 d_ptr(new QPaintEnginePrivate)
667{
668 d_ptr->q_ptr = this;
669}
670
671/*!
672 \internal
673*/
674
675QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps)
676 : state(nullptr),
677 gccaps(caps),
678 active(0),
679 selfDestruct(false),
680 extended(false),
681 d_ptr(&dptr)
682{
683 d_ptr->q_ptr = this;
684}
685
686/*!
687 Destroys the paint engine.
688*/
689QPaintEngine::~QPaintEngine()
690{
691}
692
693/*!
694 Returns the paint engine's painter.
695*/
696QPainter *QPaintEngine::painter() const
697{
698 return state ? state->painter() : nullptr;
699}
700
701/*!
702 The default implementation ignores the \a path and does nothing.
703*/
704
705void QPaintEngine::drawPath(const QPainterPath &)
706{
707 if (hasFeature(feature: PainterPaths)) {
708 qWarning(msg: "QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set");
709 }
710}
711
712/*!
713 This function draws the text item \a textItem at position \a p. The
714 default implementation of this function converts the text to a
715 QPainterPath and paints the resulting path.
716*/
717
718void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
719{
720 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
721 if (ti.glyphs.numGlyphs == 0)
722 return;
723
724 if (ti.fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
725 QVarLengthArray<QFixedPoint> positions;
726 QVarLengthArray<glyph_t> glyphs;
727 QTransform matrix = QTransform::fromTranslate(dx: p.x(), dy: p.y() - ti.fontEngine->ascent().toReal());
728 ti.fontEngine->getGlyphPositions(glyphs: ti.glyphs, matrix, flags: ti.flags, glyphs_out&: glyphs, positions);
729 painter()->save();
730 painter()->setRenderHint(hint: QPainter::SmoothPixmapTransform,
731 on: bool((painter()->renderHints() & QPainter::TextAntialiasing)
732 && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
733 for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
734 QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], subPixelPosition: QFixedPoint(), t: QTransform());
735 painter()->drawImage(x: positions[i].x.toReal(), y: positions[i].y.toReal(), image: glyph);
736 }
737 painter()->restore();
738 return;
739 }
740
741 QPainterPath path;
742 path.setFillRule(Qt::WindingFill);
743 ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, flags: ti.flags);
744 if (!path.isEmpty()) {
745 painter()->save();
746 painter()->setRenderHint(hint: QPainter::Antialiasing,
747 on: bool((painter()->renderHints() & QPainter::TextAntialiasing)
748 && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
749 painter()->translate(dx: p.x(), dy: p.y());
750 painter()->fillPath(path, brush: painter()->pen().brush());
751 painter()->restore();
752 }
753}
754
755/*!
756 The default implementation splits the list of lines in \a lines
757 into \a lineCount separate calls to drawPath() or drawPolygon()
758 depending on the feature set of the paint engine.
759*/
760void QPaintEngine::drawLines(const QLineF *lines, int lineCount)
761{
762 for (int i=0; i<lineCount; ++i) {
763 QPointF pts[2] = { lines[i].p1(), lines[i].p2() };
764
765 if (pts[0] == pts[1]) {
766 if (state->pen().capStyle() != Qt::FlatCap)
767 drawPoints(points: pts, pointCount: 1);
768 continue;
769 }
770
771 drawPolygon(points: pts, pointCount: 2, mode: PolylineMode);
772 }
773}
774
775/*!
776 \overload
777
778 The default implementation converts the first \a lineCount lines
779 in \a lines to a QLineF and calls the floating point version of
780 this function.
781*/
782void QPaintEngine::drawLines(const QLine *lines, int lineCount)
783{
784 struct PointF {
785 qreal x;
786 qreal y;
787 };
788 struct LineF {
789 PointF p1;
790 PointF p2;
791 };
792 Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
793 Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
794 LineF fl[256];
795 while (lineCount) {
796 int i = 0;
797 while (i < lineCount && i < 256) {
798 fl[i].p1.x = lines[i].x1();
799 fl[i].p1.y = lines[i].y1();
800 fl[i].p2.x = lines[i].x2();
801 fl[i].p2.y = lines[i].y2();
802 ++i;
803 }
804 drawLines(lines: (QLineF *)(void *)fl, lineCount: i);
805 lines += i;
806 lineCount -= i;
807 }
808}
809
810
811/*!
812 \overload
813
814 The default implementation converts the first \a rectCount
815 rectangles in the buffer \a rects to a QRectF and calls the
816 floating point version of this function.
817*/
818void QPaintEngine::drawRects(const QRect *rects, int rectCount)
819{
820 struct RectF {
821 qreal x;
822 qreal y;
823 qreal w;
824 qreal h;
825 };
826 Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
827 RectF fr[256];
828 while (rectCount) {
829 int i = 0;
830 while (i < rectCount && i < 256) {
831 fr[i].x = rects[i].x();
832 fr[i].y = rects[i].y();
833 fr[i].w = rects[i].width();
834 fr[i].h = rects[i].height();
835 ++i;
836 }
837 drawRects(rects: (QRectF *)(void *)fr, rectCount: i);
838 rects += i;
839 rectCount -= i;
840 }
841}
842
843/*!
844 Draws the first \a rectCount rectangles in the buffer \a
845 rects. The default implementation of this function calls drawPath()
846 or drawPolygon() depending on the feature set of the paint engine.
847*/
848void QPaintEngine::drawRects(const QRectF *rects, int rectCount)
849{
850 if (hasFeature(feature: PainterPaths) &&
851 !state->penNeedsResolving() &&
852 !state->brushNeedsResolving()) {
853 for (int i=0; i<rectCount; ++i) {
854 QPainterPath path;
855 path.addRect(rect: rects[i]);
856 if (path.isEmpty())
857 continue;
858 drawPath(path);
859 }
860 } else {
861 for (int i=0; i<rectCount; ++i) {
862 QRectF rf = rects[i];
863 QPointF pts[4] = { QPointF(rf.x(), rf.y()),
864 QPointF(rf.x() + rf.width(), rf.y()),
865 QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
866 QPointF(rf.x(), rf.y() + rf.height()) };
867 drawPolygon(points: pts, pointCount: 4, mode: ConvexMode);
868 }
869 }
870}
871
872/*!
873 \internal
874 Sets the paintdevice that this engine operates on to \a device
875*/
876void QPaintEngine::setPaintDevice(QPaintDevice *device)
877{
878 d_func()->pdev = device;
879}
880
881/*!
882 Returns the device that this engine is painting on, if painting is
883 active; otherwise returns \nullptr.
884*/
885QPaintDevice *QPaintEngine::paintDevice() const
886{
887 return d_func()->pdev;
888}
889
890
891/*!
892 \internal
893
894 Returns the offset from the painters origo to the engines
895 origo. This value is used by QPainter for engines who have
896 internal double buffering.
897
898 This function only makes sense when the engine is active.
899*/
900QPoint QPaintEngine::coordinateOffset() const
901{
902 return QPoint();
903}
904
905/*!
906 \internal
907
908 Sets the system clip for this engine. The system clip defines the
909 basis area that the engine has to draw in. All clips that are
910 set will be an intersection with the system clip.
911
912 Reset the systemclip to no clip by setting an empty region.
913*/
914void QPaintEngine::setSystemClip(const QRegion &region)
915{
916 Q_D(QPaintEngine);
917 d->baseSystemClip = region;
918 // Be backward compatible and only call d->systemStateChanged()
919 // if we currently have a system transform/viewport set.
920 d->updateSystemClip();
921 if (d->hasSystemTransform || d->hasSystemViewport) {
922 d->systemStateChanged();
923 }
924}
925
926/*!
927 \internal
928
929 Returns the system clip. The system clip is read only while the
930 painter is active. An empty region indicates that system clip
931 is not in use.
932*/
933
934QRegion QPaintEngine::systemClip() const
935{
936 return d_func()->systemClip;
937}
938
939/*!
940 \internal
941
942 Sets the target rect for drawing within the backing store. This
943 function should ONLY be used by the backing store.
944*/
945void QPaintEngine::setSystemRect(const QRect &rect)
946{
947 if (isActive()) {
948 qWarning(msg: "QPaintEngine::setSystemRect: Should not be changed while engine is active");
949 return;
950 }
951 d_func()->systemRect = rect;
952}
953
954/*!
955 \internal
956
957 Retrieves the rect for drawing within the backing store. This
958 function should ONLY be used by the backing store.
959 */
960QRect QPaintEngine::systemRect() const
961{
962 return d_func()->systemRect;
963}
964
965/*!
966 \internal
967
968 Creates a QPixmap optimized for this paint engine and device.
969*/
970QPixmap QPaintEngine::createPixmap(QSize size)
971{
972 if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
973 qWarning(msg: "QPaintEngine::createPixmap: QPixmap cannot be created without a QGuiApplication");
974 return QPixmap();
975 }
976
977 std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(type: QPlatformPixmap::PixmapType));
978 data->resize(width: size.width(), height: size.height());
979 return QPixmap(data.release());
980}
981
982/*!
983 \internal
984
985 Creates a QPixmap optimized for this paint engine and device.
986*/
987QPixmap QPaintEngine::createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags)
988{
989 if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
990 qWarning(msg: "QPaintEngine::createPixmapFromImage: QPixmap cannot be created without a QGuiApplication");
991 return QPixmap();
992 }
993
994 std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(type: QPlatformPixmap::PixmapType));
995 if (image.isDetached())
996 data->fromImageInPlace(image, flags);
997 else
998 data->fromImage(image, flags);
999 return QPixmap(data.release());
1000}
1001
1002QPaintEnginePrivate::~QPaintEnginePrivate()
1003{
1004}
1005
1006void QPaintEnginePrivate::drawBoxTextItem(const QPointF &p, const QTextItemInt &ti)
1007{
1008 if (!ti.glyphs.numGlyphs)
1009 return;
1010
1011 // any fixes here should probably also be done in QFontEngineBox::draw
1012 const int size = qRound(f: ti.fontEngine->ascent());
1013 QVarLengthArray<QFixedPoint> positions;
1014 QVarLengthArray<glyph_t> glyphs;
1015 QTransform matrix = QTransform::fromTranslate(dx: p.x(), dy: p.y() - size);
1016 ti.fontEngine->getGlyphPositions(glyphs: ti.glyphs, matrix, flags: ti.flags, glyphs_out&: glyphs, positions);
1017 if (glyphs.size() == 0)
1018 return;
1019
1020 QSize s(size - 3, size - 3);
1021
1022 QPainter *painter = q_func()->state->painter();
1023 painter->save();
1024 painter->setBrush(Qt::NoBrush);
1025 QPen pen = painter->pen();
1026 pen.setWidthF(ti.fontEngine->lineThickness().toReal());
1027 painter->setPen(pen);
1028 for (int k = 0; k < positions.size(); k++)
1029 painter->drawRect(rect: QRectF(positions[k].toPointF(), s));
1030 painter->restore();
1031}
1032
1033QT_END_NAMESPACE
1034

source code of qtbase/src/gui/painting/qpaintengine.cpp