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

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