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 \overload
485
486 The default implementation of this function calls the floating
487 point version of this function
488*/
489void QPaintEngine::drawEllipse(const QRect &rect)
490{
491 drawEllipse(rect: QRectF(rect));
492}
493
494/*!
495 \fn void QPaintEngine::drawPixmap(const QRectF &r, const QPixmap
496 &pm, const QRectF &sr)
497
498 Reimplement this function to draw the part of the \a pm
499 specified by the \a sr rectangle in the given \a r.
500*/
501
502
503void qt_fill_tile(QPixmap *tile, const QPixmap &pixmap)
504{
505 QPainter p(tile);
506 p.drawPixmap(x: 0, y: 0, pm: pixmap);
507 int x = pixmap.width();
508 while (x < tile->width()) {
509 p.drawPixmap(x, y: 0, pm: *tile, sx: 0, sy: 0, sw: x, sh: pixmap.height());
510 x *= 2;
511 }
512 int y = pixmap.height();
513 while (y < tile->height()) {
514 p.drawPixmap(x: 0, y, pm: *tile, sx: 0, sy: 0, sw: tile->width(), sh: y);
515 y *= 2;
516 }
517}
518
519Q_GUI_EXPORT void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
520 const QPixmap &pixmap, qreal xOffset, qreal yOffset)
521{
522 qreal yPos, xPos, drawH, drawW, yOff, xOff;
523 yPos = y;
524 yOff = yOffset;
525 while(yPos < y + h) {
526 drawH = pixmap.height() - yOff; // Cropping first row
527 if (yPos + drawH > y + h) // Cropping last row
528 drawH = y + h - yPos;
529 xPos = x;
530 xOff = xOffset;
531 while(xPos < x + w) {
532 drawW = pixmap.width() - xOff; // Cropping first column
533 if (xPos + drawW > x + w) // Cropping last column
534 drawW = x + w - xPos;
535 if (drawW > 0 && drawH > 0)
536 gc->drawPixmap(r: QRectF(xPos, yPos, drawW, drawH), pm: pixmap, sr: QRectF(xOff, yOff, drawW, drawH));
537 xPos += drawW;
538 xOff = 0;
539 }
540 yPos += drawH;
541 yOff = 0;
542 }
543}
544
545
546/*!
547 Reimplement this function to draw the \a pixmap in the given \a
548 rect, starting at the given \a p. The pixmap will be
549 drawn repeatedly until the \a rect is filled.
550*/
551void QPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p)
552{
553 int sw = pixmap.width();
554 int sh = pixmap.height();
555
556 if (sw*sh < 8192 && sw*sh < 16*rect.width()*rect.height()) {
557 int tw = sw, th = sh;
558 while (tw*th < 32678 && tw < rect.width()/2)
559 tw *= 2;
560 while (tw*th < 32678 && th < rect.height()/2)
561 th *= 2;
562 QPixmap tile;
563 if (pixmap.depth() == 1) {
564 tile = QBitmap(tw, th);
565 } else {
566 tile = QPixmap(tw, th);
567 if (pixmap.hasAlphaChannel())
568 tile.fill(fillColor: Qt::transparent);
569 }
570 qt_fill_tile(tile: &tile, pixmap);
571 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());
572 } else {
573 qt_draw_tile(gc: this, x: rect.x(), y: rect.y(), w: rect.width(), h: rect.height(), pixmap, xOffset: p.x(), yOffset: p.y());
574 }
575}
576
577/*!
578 \fn void QPaintEngine::drawImage(const QRectF &rectangle, const QImage
579 &image, const QRectF &sr, Qt::ImageConversionFlags flags)
580
581 Reimplement this function to draw the part of the \a image
582 specified by the \a sr rectangle in the given \a rectangle using
583 the given conversion flags \a flags, to convert it to a pixmap.
584*/
585
586void QPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
587 Qt::ImageConversionFlags flags)
588{
589 QRectF baseSize(0, 0, image.width(), image.height());
590 QImage im = image;
591 if (baseSize != sr)
592 im = im.copy(x: qFloor(v: sr.x()), y: qFloor(v: sr.y()),
593 w: qCeil(v: sr.width()), h: qCeil(v: sr.height()));
594 QPixmap pm = QPixmap::fromImage(image: im, flags);
595 drawPixmap(r, pm, sr: QRectF(QPointF(0, 0), pm.size()));
596}
597
598/*!
599 \fn Type QPaintEngine::type() const
600
601 Reimplement this function to return the paint engine \l{Type}.
602*/
603
604/*!
605 \fn void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h);
606
607 \internal
608*/
609
610/*!
611 \fn bool QPaintEngine::testDirty(DirtyFlags df)
612
613 \internal
614*/
615
616/*!
617 \fn void QPaintEngine::clearDirty(DirtyFlags df)
618
619 \internal
620*/
621
622/*!
623 \fn void QPaintEngine::setDirty(DirtyFlags df)
624
625 \internal
626*/
627
628/*!
629 \fn bool QPaintEngine::hasFeature(PaintEngineFeatures feature) const
630
631 Returns \c true if the paint engine supports the specified \a
632 feature; otherwise returns \c false.
633*/
634
635/*!
636 \fn bool QPaintEngine::isExtended() const
637
638 \internal
639
640 Returns \c true if the paint engine is a QPaintEngineEx derivative.
641*/
642
643/*!
644 \fn void QPaintEngine::updateState(const QPaintEngineState &state)
645
646 Reimplement this function to update the state of a paint engine.
647
648 When implemented, this function is responsible for checking the
649 paint engine's current \a state and update the properties that are
650 changed. Use the QPaintEngineState::state() function to find out
651 which properties that must be updated, then use the corresponding
652 \l {GetFunction}{get function} to retrieve the current values for
653 the given properties.
654
655 \sa QPaintEngineState
656*/
657
658/*!
659 Creates a paint engine with the featureset specified by \a caps.
660*/
661
662QPaintEngine::QPaintEngine(PaintEngineFeatures caps)
663 : state(nullptr),
664 gccaps(caps),
665 active(0),
666 selfDestruct(false),
667 extended(false),
668 d_ptr(new QPaintEnginePrivate)
669{
670 d_ptr->q_ptr = this;
671}
672
673/*!
674 \internal
675*/
676
677QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps)
678 : state(nullptr),
679 gccaps(caps),
680 active(0),
681 selfDestruct(false),
682 extended(false),
683 d_ptr(&dptr)
684{
685 d_ptr->q_ptr = this;
686}
687
688/*!
689 Destroys the paint engine.
690*/
691QPaintEngine::~QPaintEngine()
692{
693}
694
695/*!
696 Returns the paint engine's painter.
697*/
698QPainter *QPaintEngine::painter() const
699{
700 return state ? state->painter() : nullptr;
701}
702
703/*!
704 The default implementation ignores the \a path and does nothing.
705*/
706
707void QPaintEngine::drawPath(const QPainterPath &)
708{
709 if (hasFeature(feature: PainterPaths)) {
710 qWarning(msg: "QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set");
711 }
712}
713
714/*!
715 This function draws the text item \a textItem at position \a p. The
716 default implementation of this function converts the text to a
717 QPainterPath and paints the resulting path.
718*/
719
720void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
721{
722 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
723 if (ti.glyphs.numGlyphs == 0)
724 return;
725
726 if (ti.fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
727 QVarLengthArray<QFixedPoint> positions;
728 QVarLengthArray<glyph_t> glyphs;
729 QTransform matrix = QTransform::fromTranslate(dx: p.x(), dy: p.y() - ti.fontEngine->ascent().toReal());
730 ti.fontEngine->getGlyphPositions(glyphs: ti.glyphs, matrix, flags: ti.flags, glyphs_out&: glyphs, positions);
731 painter()->save();
732 painter()->setRenderHint(hint: QPainter::SmoothPixmapTransform,
733 on: bool((painter()->renderHints() & QPainter::TextAntialiasing)
734 && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
735 for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
736 QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], subPixelPosition: QFixedPoint(), t: QTransform());
737 painter()->drawImage(x: positions[i].x.toReal(), y: positions[i].y.toReal(), image: glyph);
738 }
739 painter()->restore();
740 return;
741 }
742
743 QPainterPath path;
744 path.setFillRule(Qt::WindingFill);
745 ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, flags: ti.flags);
746 if (!path.isEmpty()) {
747 painter()->save();
748 painter()->setRenderHint(hint: QPainter::Antialiasing,
749 on: bool((painter()->renderHints() & QPainter::TextAntialiasing)
750 && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
751 painter()->translate(dx: p.x(), dy: p.y());
752 painter()->fillPath(path, brush: painter()->pen().brush());
753 painter()->restore();
754 }
755}
756
757/*!
758 The default implementation splits the list of lines in \a lines
759 into \a lineCount separate calls to drawPath() or drawPolygon()
760 depending on the feature set of the paint engine.
761*/
762void QPaintEngine::drawLines(const QLineF *lines, int lineCount)
763{
764 for (int i=0; i<lineCount; ++i) {
765 QPointF pts[2] = { lines[i].p1(), lines[i].p2() };
766
767 if (pts[0] == pts[1]) {
768 if (state->pen().capStyle() != Qt::FlatCap)
769 drawPoints(points: pts, pointCount: 1);
770 continue;
771 }
772
773 drawPolygon(points: pts, pointCount: 2, mode: PolylineMode);
774 }
775}
776
777/*!
778 \overload
779
780 The default implementation converts the first \a lineCount lines
781 in \a lines to a QLineF and calls the floating point version of
782 this function.
783*/
784void QPaintEngine::drawLines(const QLine *lines, int lineCount)
785{
786 struct PointF {
787 qreal x;
788 qreal y;
789 };
790 struct LineF {
791 PointF p1;
792 PointF p2;
793 };
794 Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
795 Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
796 LineF fl[256];
797 while (lineCount) {
798 int i = 0;
799 while (i < lineCount && i < 256) {
800 fl[i].p1.x = lines[i].x1();
801 fl[i].p1.y = lines[i].y1();
802 fl[i].p2.x = lines[i].x2();
803 fl[i].p2.y = lines[i].y2();
804 ++i;
805 }
806 drawLines(lines: (QLineF *)(void *)fl, lineCount: i);
807 lines += i;
808 lineCount -= i;
809 }
810}
811
812
813/*!
814 \overload
815
816 The default implementation converts the first \a rectCount
817 rectangles in the buffer \a rects to a QRectF and calls the
818 floating point version of this function.
819*/
820void QPaintEngine::drawRects(const QRect *rects, int rectCount)
821{
822 struct RectF {
823 qreal x;
824 qreal y;
825 qreal w;
826 qreal h;
827 };
828 Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
829 RectF fr[256];
830 while (rectCount) {
831 int i = 0;
832 while (i < rectCount && i < 256) {
833 fr[i].x = rects[i].x();
834 fr[i].y = rects[i].y();
835 fr[i].w = rects[i].width();
836 fr[i].h = rects[i].height();
837 ++i;
838 }
839 drawRects(rects: (QRectF *)(void *)fr, rectCount: i);
840 rects += i;
841 rectCount -= i;
842 }
843}
844
845/*!
846 Draws the first \a rectCount rectangles in the buffer \a
847 rects. The default implementation of this function calls drawPath()
848 or drawPolygon() depending on the feature set of the paint engine.
849*/
850void QPaintEngine::drawRects(const QRectF *rects, int rectCount)
851{
852 if (hasFeature(feature: PainterPaths) &&
853 !state->penNeedsResolving() &&
854 !state->brushNeedsResolving()) {
855 for (int i=0; i<rectCount; ++i) {
856 QPainterPath path;
857 path.addRect(rect: rects[i]);
858 if (path.isEmpty())
859 continue;
860 drawPath(path);
861 }
862 } else {
863 for (int i=0; i<rectCount; ++i) {
864 QRectF rf = rects[i];
865 QPointF pts[4] = { QPointF(rf.x(), rf.y()),
866 QPointF(rf.x() + rf.width(), rf.y()),
867 QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
868 QPointF(rf.x(), rf.y() + rf.height()) };
869 drawPolygon(points: pts, pointCount: 4, mode: ConvexMode);
870 }
871 }
872}
873
874/*!
875 \internal
876 Sets the paintdevice that this engine operates on to \a device
877*/
878void QPaintEngine::setPaintDevice(QPaintDevice *device)
879{
880 d_func()->pdev = device;
881}
882
883/*!
884 Returns the device that this engine is painting on, if painting is
885 active; otherwise returns \nullptr.
886*/
887QPaintDevice *QPaintEngine::paintDevice() const
888{
889 return d_func()->pdev;
890}
891
892
893/*!
894 \internal
895
896 Returns the offset from the painters origo to the engines
897 origo. This value is used by QPainter for engines who have
898 internal double buffering.
899
900 This function only makes sense when the engine is active.
901*/
902QPoint QPaintEngine::coordinateOffset() const
903{
904 return QPoint();
905}
906
907/*!
908 \internal
909
910 Sets the system clip for this engine. The system clip defines the
911 basis area that the engine has to draw in. All clips that are
912 set will be an intersection with the system clip.
913
914 Reset the systemclip to no clip by setting an empty region.
915*/
916void QPaintEngine::setSystemClip(const QRegion &region)
917{
918 Q_D(QPaintEngine);
919 d->baseSystemClip = region;
920 // Be backward compatible and only call d->systemStateChanged()
921 // if we currently have a system transform/viewport set.
922 d->updateSystemClip();
923 if (d->hasSystemTransform || d->hasSystemViewport) {
924 d->systemStateChanged();
925 }
926}
927
928/*!
929 \internal
930
931 Returns the system clip. The system clip is read only while the
932 painter is active. An empty region indicates that system clip
933 is not in use.
934*/
935
936QRegion QPaintEngine::systemClip() const
937{
938 return d_func()->systemClip;
939}
940
941/*!
942 \internal
943
944 Sets the target rect for drawing within the backing store. This
945 function should ONLY be used by the backing store.
946*/
947void QPaintEngine::setSystemRect(const QRect &rect)
948{
949 if (isActive()) {
950 qWarning(msg: "QPaintEngine::setSystemRect: Should not be changed while engine is active");
951 return;
952 }
953 d_func()->systemRect = rect;
954}
955
956/*!
957 \internal
958
959 Retrieves the rect for drawing within the backing store. This
960 function should ONLY be used by the backing store.
961 */
962QRect QPaintEngine::systemRect() const
963{
964 return d_func()->systemRect;
965}
966
967/*!
968 \internal
969
970 Creates a QPixmap optimized for this paint engine and device.
971*/
972QPixmap QPaintEngine::createPixmap(QSize size)
973{
974 if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
975 qWarning(msg: "QPaintEngine::createPixmap: QPixmap cannot be created without a QGuiApplication");
976 return QPixmap();
977 }
978
979 std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(type: QPlatformPixmap::PixmapType));
980 data->resize(width: size.width(), height: size.height());
981 return QPixmap(data.release());
982}
983
984/*!
985 \internal
986
987 Creates a QPixmap optimized for this paint engine and device.
988*/
989QPixmap QPaintEngine::createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags)
990{
991 if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
992 qWarning(msg: "QPaintEngine::createPixmapFromImage: QPixmap cannot be created without a QGuiApplication");
993 return QPixmap();
994 }
995
996 std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(type: QPlatformPixmap::PixmapType));
997 if (image.isDetached())
998 data->fromImageInPlace(image, flags);
999 else
1000 data->fromImage(image, flags);
1001 return QPixmap(data.release());
1002}
1003
1004QPaintEnginePrivate::~QPaintEnginePrivate()
1005{
1006}
1007
1008void QPaintEnginePrivate::drawBoxTextItem(const QPointF &p, const QTextItemInt &ti)
1009{
1010 if (!ti.glyphs.numGlyphs)
1011 return;
1012
1013 // any fixes here should probably also be done in QFontEngineBox::draw
1014 const int size = qRound(f: ti.fontEngine->ascent());
1015 QVarLengthArray<QFixedPoint> positions;
1016 QVarLengthArray<glyph_t> glyphs;
1017 QTransform matrix = QTransform::fromTranslate(dx: p.x(), dy: p.y() - size);
1018 ti.fontEngine->getGlyphPositions(glyphs: ti.glyphs, matrix, flags: ti.flags, glyphs_out&: glyphs, positions);
1019 if (glyphs.size() == 0)
1020 return;
1021
1022 QSize s(size - 3, size - 3);
1023
1024 QPainter *painter = q_func()->state->painter();
1025 painter->save();
1026 painter->setBrush(Qt::NoBrush);
1027 QPen pen = painter->pen();
1028 pen.setWidthF(ti.fontEngine->lineThickness().toReal());
1029 painter->setPen(pen);
1030 for (int k = 0; k < positions.size(); k++)
1031 painter->drawRect(rect: QRectF(positions[k].toPointF(), s));
1032 painter->restore();
1033}
1034
1035QT_END_NAMESPACE
1036

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