Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpaintengine_alpha.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
5
6#ifndef QT_NO_PRINTER
7#include <qdebug.h>
8#include "private/qpaintengine_alpha_p.h"
9
10#include "private/qpainter_p.h"
11#include "private/qpicture_p.h"
12#include "private/qfont_p.h"
13#include "QtGui/qpicture.h"
14
16
18 : QPaintEngine(data, devcaps)
19{
20
21}
22
27
29{
31
32 d->m_continueCall = true;
33 if (d->m_pass != 0) {
34 return true;
35 }
36
37 d->m_savedcaps = gccaps;
38 d->m_pdev = pdev;
39
40 d->m_alphaPen = false;
41 d->m_alphaBrush = false;
42 d->m_alphaOpacity = false;
43 d->m_hasalpha = false;
44 d->m_advancedPen = false;
45 d->m_advancedBrush = false;
46 d->m_complexTransform = false;
47 d->m_emulateProjectiveTransforms = false;
48
49 // clear alpha region
50 d->m_alphargn = QRegion();
51 d->m_cliprgn = QRegion();
52 d->m_pen = QPen();
53 d->m_transform = QTransform();
54
56
57 return true;
58}
59
61{
63
64 d->m_continueCall = true;
65 if (d->m_pass != 0) {
66 return true;
67 }
68
69 flushAndInit(false);
70 return true;
71}
72
74{
76
77 DirtyFlags flags = state.state();
79 d->m_transform = state.transform();
80 d->m_complexTransform = (d->m_transform.type() > QTransform::TxScale);
81 d->m_emulateProjectiveTransforms = !(d->m_savedcaps & QPaintEngine::PerspectiveTransform)
82 && !(d->m_savedcaps & QPaintEngine::AlphaBlend)
83 && (d->m_transform.type() >= QTransform::TxProject);
84 }
86 d->m_pen = state.pen();
87 if (d->m_pen.style() == Qt::NoPen) {
88 d->m_advancedPen = false;
89 d->m_alphaPen = false;
90 } else {
91 d->m_advancedPen = (d->m_pen.brush().style() != Qt::SolidPattern);
92 d->m_alphaPen = !d->m_pen.brush().isOpaque();
93 }
94 }
95
96 if (d->m_pass != 0) {
97 d->m_continueCall = true;
98 return;
99 }
100 d->m_continueCall = false;
101
103 d->m_alphaOpacity = (state.opacity() != 1.0f);
104 }
105
107 if (state.brush().style() == Qt::NoBrush) {
108 d->m_advancedBrush = false;
109 d->m_alphaBrush = false;
110 } else {
111 d->m_advancedBrush = (state.brush().style() != Qt::SolidPattern);
112 d->m_alphaBrush = !state.brush().isOpaque();
113 }
114 }
115
116
117 d->m_hasalpha = d->m_alphaOpacity || d->m_alphaBrush || d->m_alphaPen;
118
119 if (d->m_picengine) {
120 const QPainter *p = painter();
121 d->m_picpainter->setPen(p->pen());
122 d->m_picpainter->setBrush(p->brush());
123 d->m_picpainter->setBrushOrigin(p->brushOrigin());
124 d->m_picpainter->setFont(p->font());
125 d->m_picpainter->setOpacity(p->opacity());
126 d->m_picpainter->setTransform(p->combinedTransform());
127 d->m_picengine->updateState(state);
128 }
129}
130
132{
134
135 QRectF tr = d->addPenWidth(path);
136
137 if (d->m_pass == 0) {
138 d->m_continueCall = false;
139 if (d->canSeeTroughBackground(d->m_hasalpha, tr) || d->m_advancedPen || d->m_advancedBrush
140 || d->m_emulateProjectiveTransforms)
141 {
142 d->addAlphaRect(tr);
143 }
144
145 d->addDirtyRect(tr);
146
147 if (d->m_picengine)
148 d->m_picengine->drawPath(path);
149 } else {
150 d->m_continueCall = !d->fullyContained(tr);
151 }
152}
153
155{
157
158 QPolygonF poly;
159 poly.reserve(pointCount);
160 for (int i = 0; i < pointCount; ++i)
161 poly.append(points[i]);
162
164 path.addPolygon(poly);
165 QRectF tr = d->addPenWidth(path);
166
167 if (d->m_pass == 0) {
168 d->m_continueCall = false;
169 if (d->canSeeTroughBackground(d->m_hasalpha, tr) || d->m_advancedPen || d->m_advancedBrush
170 || d->m_emulateProjectiveTransforms)
171 {
172 d->addAlphaRect(tr);
173 }
174
175 d->addDirtyRect(tr);
176
177 if (d->m_picengine)
178 d->m_picengine->drawPolygon(points, pointCount, mode);
179 } else {
180 d->m_continueCall = !d->fullyContained(tr);
181 }
182}
183
184void QAlphaPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
185{
187
188 QRectF tr = d->m_transform.mapRect(r);
189 if (d->m_pass == 0) {
190 d->m_continueCall = false;
191 if (d->canSeeTroughBackground(pm.hasAlpha() || d->m_alphaOpacity, tr) || d->m_complexTransform || pm.isQBitmap()) {
192 d->addAlphaRect(tr);
193 }
194
195 d->addDirtyRect(tr);
196
197 if (d->m_picengine)
198 d->m_picengine->drawPixmap(r, pm, sr);
199
200 } else {
201 d->m_continueCall = !d->fullyContained(tr);
202 }
203}
204
206{
208
209 QRectF tr(p.x(), p.y() - textItem.ascent(), textItem.width() + 5, textItem.ascent() + textItem.descent() + 5);
210 tr = d->m_transform.mapRect(tr);
211
212 if (d->m_pass == 0) {
213 d->m_continueCall = false;
214 if (d->canSeeTroughBackground(d->m_alphaPen || d->m_alphaOpacity, tr) || d->m_advancedPen) {
215 d->addAlphaRect(tr);
216 }
217
218 d->addDirtyRect(tr);
219
220 if (d->m_picengine) {
221 d->m_picengine->drawTextItem(p, textItem);
222 }
223 } else {
224 d->m_continueCall = !d->fullyContained(tr);
225 }
226}
227
229{
231
232 QRectF brect = d->m_transform.mapRect(r);
233
234 if (d->m_pass == 0) {
235 d->m_continueCall = false;
236 if (d->canSeeTroughBackground(pixmap.hasAlpha() || d->m_alphaOpacity, brect) || d->m_complexTransform || pixmap.isQBitmap()) {
237 d->addAlphaRect(brect);
238 }
239
240 d->addDirtyRect(brect);
241
242 if (d->m_picengine)
243 d->m_picengine->drawTiledPixmap(r, pixmap, s);
244 } else {
245 d->m_continueCall = !d->fullyContained(brect);
246 }
247}
248
250{
251 Q_D(const QAlphaPaintEngine);
252 return d->m_cliprgn;
253}
254
256{
257 Q_D(const QAlphaPaintEngine);
258 return d->m_continueCall;
259}
260
262{
264 Q_ASSERT(d->m_pass == 0);
265
266 if (d->m_pic) {
267 d->m_picpainter->end();
268
269 // set clip region
270 d->m_alphargn = d->m_alphargn.intersected(QRect(0, 0, d->m_pdev->width(), d->m_pdev->height()));
271
272 // just use the bounding rect if it's a complex region..
273 if (d->m_alphargn.rectCount() > 10) {
274 QRect br = d->m_alphargn.boundingRect();
275 d->m_alphargn = QRegion(br);
276 }
277
278 const auto oldAlphaRegion = d->m_cliprgn = d->m_alphargn;
279
280 // now replay the QPicture
281 ++d->m_pass; // we are now doing pass #2
282
283 // reset states
284 gccaps = d->m_savedcaps;
285
286 painter()->save();
287 d->resetState(painter());
288
289 // make sure the output from QPicture is unscaled
290 QTransform mtx;
291 mtx.scale(1.0f / (qreal(d->m_pdev->logicalDpiX()) / qreal(qt_defaultDpiX())),
292 1.0f / (qreal(d->m_pdev->logicalDpiY()) / qreal(qt_defaultDpiY())));
293 painter()->setTransform(mtx);
294 painter()->drawPicture(0, 0, *d->m_pic);
295
296 d->m_cliprgn = QRegion();
297 d->resetState(painter());
298
299 // fill in the alpha images
300 for (const auto &rect : oldAlphaRegion)
301 d->drawAlphaImage(rect);
302
303 d->m_alphargn = QRegion();
304
305 painter()->restore();
306
307 --d->m_pass; // pass #2 finished
308
309 cleanUp();
310 }
311
312 if (init) {
314
315 d->m_pic = new QPicture();
316 d->m_pic->d_ptr->in_memory_only = true;
317 d->m_picpainter = new QPainter(d->m_pic);
318 d->m_picengine = d->m_picpainter->paintEngine();
319
320 // When newPage() is called and the m_picpainter is recreated
321 // we have to copy the current state of the original printer
322 // painter back to the m_picpainter
323 d->m_picpainter->setPen(painter()->pen());
324 d->m_picpainter->setBrush(painter()->brush());
325 d->m_picpainter->setBrushOrigin(painter()->brushOrigin());
326 d->m_picpainter->setFont(painter()->font());
327 d->m_picpainter->setOpacity(painter()->opacity());
328 d->m_picpainter->setTransform(painter()->combinedTransform());
329 d->m_picengine->syncState();
330 QPainterState &state = *d->m_picpainter->d_func()->state;
331 QPainter *oldPainter = state.painter;
332 state = *painter()->d_func()->state;
333 state.painter = oldPainter;
334 }
335}
336
338{
340
341 delete d->m_picpainter;
342 delete d->m_pic;
343
344 d->m_picpainter = nullptr;
345 d->m_pic = nullptr;
346 d->m_picengine = nullptr;
347}
348
350 : m_pass(0),
351 m_pic(nullptr),
352 m_picengine(nullptr),
353 m_picpainter(nullptr),
354 m_numberOfCachedRects(0),
355 m_hasalpha(false),
356 m_alphaPen(false),
357 m_alphaBrush(false),
358 m_alphaOpacity(false),
359 m_advancedPen(false),
360 m_advancedBrush(false),
361 m_complexTransform(false)
362{
363
364}
365
371
373{
374 QPainterPath tmp = path;
375
376 if (m_pen.style() == Qt::NoPen)
377 return (path.controlPointRect() * m_transform).boundingRect();
378 bool cosmetic = m_pen.isCosmetic();
379 if (cosmetic)
380 tmp = path * m_transform;
381
382 QPainterPathStroker stroker;
383 if (m_pen.widthF() == 0.0f)
384 stroker.setWidth(1.0);
385 else
386 stroker.setWidth(m_pen.widthF());
387 stroker.setJoinStyle(m_pen.joinStyle());
388 stroker.setCapStyle(m_pen.capStyle());
389 tmp = stroker.createStroke(tmp);
390 if (cosmetic)
391 return tmp.controlPointRect();
392
393 return (tmp.controlPointRect() * m_transform).boundingRect();
394}
395
397{
398 m_alphargn |= rect.toAlignedRect();
399}
400
401bool QAlphaPaintEnginePrivate::canSeeTroughBackground(bool somethingInRectHasAlpha, const QRectF &rect) const
402{
403 if (somethingInRectHasAlpha) {
407 }
408 return m_cachedDirtyRgn.intersects(rect.toAlignedRect());
409 }
410 return false;
411}
412
414{
416
417 qreal dpiX = qMax(m_pdev->logicalDpiX(), 300);
418 qreal dpiY = qMax(m_pdev->logicalDpiY(), 300);
419 qreal xscale = (dpiX / m_pdev->logicalDpiX());
420 qreal yscale = (dpiY / m_pdev->logicalDpiY());
421
422 QTransform picscale;
423 picscale.scale(xscale, yscale);
424
425 const int tileSize = 2048;
426 QSize size((int(rect.width() * xscale)), int(rect.height() * yscale));
427 int divw = (size.width() / tileSize);
428 int divh = (size.height() / tileSize);
429 divw += 1;
430 divh += 1;
431
432 int incx = int(rect.width() / divw);
433 int incy = int(rect.height() / divh);
434
435 for (int y=0; y<divh; ++y) {
436 int ypos = int((incy * y) + rect.y());
437 int height = int((y == (divh - 1)) ? (rect.height() - (incy * y)) : incy) + 1;
438
439 for (int x=0; x<divw; ++x) {
440 int xpos = int((incx * x) + rect.x());
441 int width = int((x == (divw - 1)) ? (rect.width() - (incx * x)) : incx) + 1;
442
443 QSize imgsize((int)(width * xscale), (int)(height * yscale));
445 img.fill(0xffffffff);
446
447 QPainter imgpainter(&img);
448 imgpainter.setTransform(picscale);
449 QPointF picpos(qreal(-xpos), qreal(-ypos));
450 imgpainter.drawPicture(picpos, *m_pic);
451 imgpainter.end();
452
453 q->painter()->setTransform(QTransform());
454 QRect r(xpos, ypos, width, height);
455 q->painter()->drawImage(r, img);
456 }
457 }
458}
459
461{
462 QRegion r(rect.toAlignedRect());
463 return (m_cliprgn.intersected(r) == r);
464}
465
467{
468 p->setPen(QPen());
469 p->setBrush(QBrush());
470 p->setBrushOrigin(0,0);
471 p->setBackground(QBrush());
472 p->setFont(QFont());
473 p->setTransform(QTransform());
474 // The view transform is already recorded and included in the
475 // picture we're about to replay. If we don't turn if off,
476 // the view matrix will be applied twice.
477 p->setViewTransformEnabled(false);
478 p->setClipRegion(QRegion(), Qt::NoClip);
479 p->setClipPath(QPainterPath(), Qt::NoClip);
480 p->setClipping(false);
481 p->setOpacity(1.0f);
482}
483
484
486
487#endif // QT_NO_PRINTER
void drawAlphaImage(const QRectF &rect)
QRectF addPenWidth(const QPainterPath &path)
void addAlphaRect(const QRectF &rect)
bool fullyContained(const QRectF &rect) const
bool canSeeTroughBackground(bool somethingInRectHasAlpha, const QRectF &rect) const
QRegion alphaClipping() const
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r.
QAlphaPaintEngine(QAlphaPaintEnginePrivate &data, PaintEngineFeatures devcaps={ })
bool end() override
Reimplement this function to finish painting on the current paint device.
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
void drawTextItem(const QPointF &p, const QTextItem &textItem) override
This function draws the text item textItem at position p.
bool begin(QPaintDevice *pdev) override
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override
Reimplement this function to draw the pixmap in the given rect, starting at the given p.
void updateState(const QPaintEngineState &state) override
Reimplement this function to update the state of a paint engine.
void drawPath(const QPainterPath &path) override
The default implementation ignores the path and does nothing.
void flushAndInit(bool init=true)
\inmodule QtGui
Definition qbrush.h:30
bool isOpaque() const
Returns true if the brush is fully opaque otherwise false.
Definition qbrush.cpp:830
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
\reentrant
Definition qfont.h:22
\inmodule QtGui
Definition qimage.h:37
@ Format_RGB32
Definition qimage.h:46
qsizetype size() const noexcept
Definition qlist.h:397
const_pointer constData() const noexcept
Definition qlist.h:433
void reserve(qsizetype size)
Definition qlist.h:753
int logicalDpiX() const
int logicalDpiY() const
The QPaintEngineState class provides information about the active paint engine's current state....
QTransform transform() const
QPainter * painter() const
Returns a pointer to the painter currently updating the paint engine.
qreal opacity() const
QBrush brush() const
Returns the brush in the current paint engine state.
QPen pen() const
Returns the pen in the current paint engine state.
QPaintEngine::DirtyFlags state() const
Returns a combination of flags identifying the set of properties that need to be updated when updatin...
\inmodule QtGui
friend class QPainter
PolygonDrawMode
\value OddEvenMode The polygon should be drawn using OddEven fill rule.
QPainter * painter() const
Returns the paint engine's painter.
@ ObjectBoundingModeGradients
QPaintEngineState * state
PaintEngineFeatures gccaps
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
\inmodule QtGui
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void restore()
Restores the current painter state (pops a saved state off the stack).
void save()
Saves the current painter state (pushes the state onto a stack).
void drawPicture(const QPointF &p, const QPicture &picture)
Replays the given picture at the given point.
void setTransform(const QTransform &transform, bool combine=false)
\inmodule QtGui
Definition qpen.h:28
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:572
bool isCosmetic() const
Returns true if the pen is cosmetic; otherwise returns false.
Definition qpen.cpp:757
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:663
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition qpen.cpp:715
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
The QPicture class is a paint device that records and replays QPainter commands.
Definition qpicture.h:19
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
bool hasAlpha() const
bool isQBitmap() const
Returns true if this is a QBitmap; otherwise returns false.
Definition qpixmap.cpp:443
\inmodule QtCore\reentrant
Definition qpoint.h:217
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
void setRects(const QRect *rect, int num)
Sets the region using the array of rectangles specified by rects and number.
bool intersects(const QRegion &r) const
Definition qregion.cpp:613
QRegion intersected(const QRegion &r) const
\inmodule QtCore
Definition qsize.h:25
\inmodule QtGui
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
rect
[4]
else opt state
[0]
Combined button and popup list for selecting options.
@ NoClip
@ NoPen
@ SolidPattern
@ NoBrush
Definition brush.cpp:5
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:110
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:125
static QT_BEGIN_NAMESPACE const int tileSize
Definition qmemrotate.cpp:9
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLenum GLenum GLuint GLint GLint GLint yscale
GLenum mode
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLenum GLenum GLuint GLint GLint xscale
GLbitfield flags
GLint y
GLfixed GLfixed GLint GLint GLfixed points
GLdouble s
[6]
Definition qopenglext.h:235
GLint void * img
Definition qopenglext.h:233
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define tr(X)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
double qreal
Definition qtypes.h:187
QObject::connect nullptr
widget render & pixmap