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