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
qquickpainteditem.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
6#include <private/qquickpainteditem_p.h>
7
8#include <QtQuick/private/qsgdefaultpainternode_p.h>
9#include <QtQuick/private/qsgcontext_p.h>
10#include <private/qsgadaptationlayer_p.h>
11#include <qsgtextureprovider.h>
12#include <rhi/qrhi.h>
13
14#include <qmath.h>
15
17
19{
20public:
22 QSGTexture *texture() const override { return node ? node->texture() : nullptr; }
23 void fireTextureChanged() { emit textureChanged(); }
24};
25
26/*!
27 \class QQuickPaintedItem
28 \brief The QQuickPaintedItem class provides a way to use the QPainter API in the
29 QML Scene Graph.
30
31 \inmodule QtQuick
32
33 The QQuickPaintedItem makes it possible to use the QPainter API with the QML
34 Scene Graph. It sets up a textured rectangle in the Scene Graph and uses a
35 QPainter to paint onto the texture. The render target in Qt 6 is always a
36 QImage. When the render target is a QImage, QPainter first renders into the
37 image then the content is uploaded to the texture. Call update() to trigger
38 a repaint.
39
40 To enable QPainter to do anti-aliased rendering, use setAntialiasing().
41
42 To write your own painted item, you first create a subclass of
43 QQuickPaintedItem, and then start by implementing its only pure virtual
44 public function: paint(), which implements the actual painting. The
45 painting will be inside the rectangle spanning from 0,0 to
46 width(),height().
47
48 \note It important to understand the performance implications such items
49 can incur. See QQuickPaintedItem::RenderTarget and
50 QQuickPaintedItem::renderTarget.
51
52 \sa {Scene Graph - Painted Item}, {Writing QML Extensions with C++}
53*/
54
55/*!
56 \enum QQuickPaintedItem::RenderTarget
57
58 This enum describes QQuickPaintedItem's render targets. The render target is the
59 surface QPainter paints onto before the item is rendered on screen.
60
61 \value Image The default; QPainter paints into a QImage using the raster paint engine.
62 The image's content needs to be uploaded to graphics memory afterward, this operation
63 can potentially be slow if the item is large. This render target allows high quality
64 anti-aliasing and fast item resizing.
65
66 \value FramebufferObject As of Qt 6.9, this value will enable
67 hardware-accelerated painting as long as the rendering API used is OpenGL,
68 otherwise it will be ignored. For versions Qt 6.0 to Qt 6.8, it will be
69 ignored on all rendering APIs. This will usually give better rendering
70 performance, but at the expense of antialiasing quality.
71
72 \value InvertedYFramebufferObject Same as FramebufferObject, but with the
73 rendering flipped around the X axis.
74
75 \sa setRenderTarget()
76*/
77
78/*!
79 \enum QQuickPaintedItem::PerformanceHint
80
81 This enum describes flags that you can enable to improve rendering
82 performance in QQuickPaintedItem. By default, none of these flags are set.
83
84 \value FastFBOResizing As of Qt 6.0, this value is ignored.
85*/
86
87/*!
88 \internal
89*/
90QQuickPaintedItemPrivate::QQuickPaintedItemPrivate()
91 : QQuickItemPrivate()
92 , contentsScale(1.0)
93 , fillColor(Qt::transparent)
94 , renderTarget(QQuickPaintedItem::Image)
95 , opaquePainting(false)
96 , mipmap(false)
97 , textureProvider(nullptr)
98 , node(nullptr)
99{
100}
101
102/*!
103 Constructs a QQuickPaintedItem with the given \a parent item.
104 */
105QQuickPaintedItem::QQuickPaintedItem(QQuickItem *parent)
106 : QQuickItem(*(new QQuickPaintedItemPrivate), parent)
107{
108 setFlag(ItemHasContents);
109}
110
111/*!
112 \internal
113*/
114QQuickPaintedItem::QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent)
115 : QQuickItem(dd, parent)
116{
117 setFlag(ItemHasContents);
118}
119
120/*!
121 Destroys the QQuickPaintedItem.
122*/
123QQuickPaintedItem::~QQuickPaintedItem()
124{
125 Q_D(QQuickPaintedItem);
126 if (d->textureProvider)
127 QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
128}
129
130/*!
131 Schedules a redraw of the area covered by \a rect in this item. You can call this function
132 whenever your item needs to be redrawn, such as if it changes appearance or size.
133
134 This function does not cause an immediate paint; instead it schedules a paint request that
135 is processed by the QML Scene Graph when the next frame is rendered. The item will only be
136 redrawn if it is visible.
137
138 \sa paint()
139*/
140void QQuickPaintedItem::update(const QRect &rect)
141{
142 Q_D(QQuickPaintedItem);
143
144 if (rect.isNull() && !d->dirtyRect.isNull())
145 d->dirtyRect = contentsBoundingRect().toAlignedRect();
146 else
147 d->dirtyRect |= (contentsBoundingRect() & rect).toAlignedRect();
148 QQuickItem::update();
149}
150
151/*!
152 Returns true if this item is opaque; otherwise, false is returned.
153
154 By default, painted items are not opaque.
155
156 \sa setOpaquePainting()
157*/
158bool QQuickPaintedItem::opaquePainting() const
159{
160 Q_D(const QQuickPaintedItem);
161 return d->opaquePainting;
162}
163
164/*!
165 If \a opaque is true, the item is opaque; otherwise, it is considered as translucent.
166
167 Opaque items are not blended with the rest of the scene, you should set this to true
168 if the content of the item is opaque to speed up rendering.
169
170 By default, painted items are not opaque.
171
172 \sa opaquePainting()
173*/
174void QQuickPaintedItem::setOpaquePainting(bool opaque)
175{
176 Q_D(QQuickPaintedItem);
177
178 if (d->opaquePainting == opaque)
179 return;
180
181 d->opaquePainting = opaque;
182 QQuickItem::update();
183}
184
185//### Qt7: remove the aa functions; they shadow the QQuickItem property
186/*!
187 Returns true if antialiased painting is enabled; otherwise, false is returned.
188
189 By default, antialiasing is not enabled.
190
191 \sa setAntialiasing()
192*/
193bool QQuickPaintedItem::antialiasing() const
194{
195 return QQuickItem::antialiasing();
196}
197
198/*!
199 If \a enable is true, antialiased painting is enabled.
200
201 By default, antialiasing is not enabled.
202
203 \sa antialiasing()
204*/
205void QQuickPaintedItem::setAntialiasing(bool enable)
206{
207 QQuickItem::setAntialiasing(enable);
208}
209
210/*!
211 Returns true if mipmaps are enabled; otherwise, false is returned.
212
213 By default, mipmapping is not enabled.
214
215 \sa setMipmap()
216*/
217bool QQuickPaintedItem::mipmap() const
218{
219 Q_D(const QQuickPaintedItem);
220 return d->mipmap;
221}
222
223/*!
224 If \a enable is true, mipmapping is enabled on the associated texture.
225
226 Mipmapping increases rendering speed and reduces aliasing artifacts when the item is
227 scaled down.
228
229 By default, mipmapping is not enabled.
230
231 \sa mipmap()
232*/
233void QQuickPaintedItem::setMipmap(bool enable)
234{
235 Q_D(QQuickPaintedItem);
236
237 if (d->mipmap == enable)
238 return;
239
240 d->mipmap = enable;
241 update();
242}
243
244/*!
245 Returns the performance hints.
246
247 By default, no performance hint is enabled.
248
249 \sa setPerformanceHint(), setPerformanceHints()
250*/
251QQuickPaintedItem::PerformanceHints QQuickPaintedItem::performanceHints() const
252{
253 Q_D(const QQuickPaintedItem);
254 return d->performanceHints;
255}
256
257/*!
258 Sets the given performance \a hint on the item if \a enabled is true;
259 otherwise clears the performance hint.
260
261 By default, no performance hint is enabled/
262
263 \sa setPerformanceHints(), performanceHints()
264*/
265void QQuickPaintedItem::setPerformanceHint(QQuickPaintedItem::PerformanceHint hint, bool enabled)
266{
267 Q_D(QQuickPaintedItem);
268 PerformanceHints oldHints = d->performanceHints;
269 if (enabled)
270 d->performanceHints |= hint;
271 else
272 d->performanceHints &= ~hint;
273 if (oldHints != d->performanceHints)
274 update();
275}
276
277/*!
278 Sets the performance hints to \a hints
279
280 By default, no performance hint is enabled/
281
282 \sa setPerformanceHint(), performanceHints()
283*/
284void QQuickPaintedItem::setPerformanceHints(QQuickPaintedItem::PerformanceHints hints)
285{
286 Q_D(QQuickPaintedItem);
287 if (d->performanceHints == hints)
288 return;
289 d->performanceHints = hints;
290 update();
291}
292
293QSize QQuickPaintedItem::textureSize() const
294{
295 Q_D(const QQuickPaintedItem);
296 return d->textureSize;
297}
298
299/*!
300 \property QQuickPaintedItem::textureSize
301
302 \brief Defines the size of the texture.
303
304 Changing the texture's size does not affect the coordinate system used in
305 paint(). A scale factor is instead applied so painting should still happen
306 inside 0,0 to width(),height().
307
308 By default, the texture size will have the same size as this item.
309
310 \note If the item is on a window with a device pixel ratio different from
311 1, this scale factor will be implicitly applied to the texture size.
312
313 */
314void QQuickPaintedItem::setTextureSize(const QSize &size)
315{
316 Q_D(QQuickPaintedItem);
317 if (d->textureSize == size)
318 return;
319 d->textureSize = size;
320 emit textureSizeChanged();
321}
322
323/*!
324 \deprecated
325
326 This function is provided for compatibility, use size in combination
327 with textureSize to decide the size of what you are drawing.
328
329 \sa width(), height(), textureSize()
330*/
331QRectF QQuickPaintedItem::contentsBoundingRect() const
332{
333 Q_D(const QQuickPaintedItem);
334
335 qreal w = d->width;
336 QSizeF sz = d->contentsSize * d->contentsScale;
337 if (w < sz.width())
338 w = sz.width();
339 qreal h = d->height;
340 if (h < sz.height())
341 h = sz.height();
342
343 return QRectF(0, 0, w, h);
344}
345
346/*!
347 \property QQuickPaintedItem::contentsSize
348 \brief Obsolete method for setting the contents size.
349 \deprecated
350
351 This function is provided for compatibility, use size in combination
352 with textureSize to decide the size of what you are drawing.
353
354 \sa width(), height(), textureSize()
355*/
356QSize QQuickPaintedItem::contentsSize() const
357{
358 Q_D(const QQuickPaintedItem);
359 return d->contentsSize;
360}
361
362void QQuickPaintedItem::setContentsSize(const QSize &size)
363{
364 Q_D(QQuickPaintedItem);
365
366 if (d->contentsSize == size)
367 return;
368
369 d->contentsSize = size;
370 update();
371
372 emit contentsSizeChanged();
373}
374
375/*!
376 \deprecated
377 This convenience function is equivalent to calling setContentsSize(QSize()).
378*/
379void QQuickPaintedItem::resetContentsSize()
380{
381 setContentsSize(QSize());
382}
383
384/*!
385 \property QQuickPaintedItem::contentsScale
386 \brief Obsolete method for scaling the contents.
387 \deprecated
388
389 This function is provided for compatibility, use size() in combination
390 with textureSize() to decide the size of what you are drawing.
391
392 \sa width(), height(), textureSize()
393*/
394qreal QQuickPaintedItem::contentsScale() const
395{
396 Q_D(const QQuickPaintedItem);
397 return d->contentsScale;
398}
399
400void QQuickPaintedItem::setContentsScale(qreal scale)
401{
402 Q_D(QQuickPaintedItem);
403
404 if (d->contentsScale == scale)
405 return;
406
407 d->contentsScale = scale;
408 update();
409
410 emit contentsScaleChanged();
411}
412
413/*!
414 \property QQuickPaintedItem::fillColor
415 \brief The item's background fill color.
416
417 By default, the fill color is set to Qt::transparent.
418
419 Set the fill color to an invalid color (e.g. QColor()) to disable background
420 filling. This may improve performance, and is safe to do if the paint() function
421 draws to all pixels on each frame.
422*/
423QColor QQuickPaintedItem::fillColor() const
424{
425 Q_D(const QQuickPaintedItem);
426 return d->fillColor;
427}
428
429void QQuickPaintedItem::setFillColor(const QColor &c)
430{
431 Q_D(QQuickPaintedItem);
432
433 if (d->fillColor == c)
434 return;
435
436 d->fillColor = c;
437 update();
438
439 emit fillColorChanged();
440}
441
442/*!
443 \property QQuickPaintedItem::renderTarget
444 \brief The item's render target.
445
446 This property defines which render target the QPainter renders into, it can be either
447 QQuickPaintedItem::Image, QQuickPaintedItem::FramebufferObject or QQuickPaintedItem::InvertedYFramebufferObject.
448
449 Each has certain benefits, typically performance versus quality. Using a framebuffer
450 object avoids a costly upload of the image contents to the texture in graphics memory,
451 while using an image enables high quality anti-aliasing.
452
453 \warning Resizing a framebuffer object is a costly operation, avoid using
454 the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
455
456 By default, the render target is QQuickPaintedItem::Image.
457*/
458QQuickPaintedItem::RenderTarget QQuickPaintedItem::renderTarget() const
459{
460 Q_D(const QQuickPaintedItem);
461 return d->renderTarget;
462}
463
464void QQuickPaintedItem::setRenderTarget(RenderTarget target)
465{
466 Q_D(QQuickPaintedItem);
467
468 if (d->renderTarget == target)
469 return;
470
471 d->renderTarget = target;
472 update();
473
474 emit renderTargetChanged();
475}
476
477/*!
478 \fn virtual void QQuickPaintedItem::paint(QPainter *painter) = 0
479
480 This function, which is usually called by the QML Scene Graph, paints the
481 contents of an item in local coordinates.
482
483 The underlying texture will have a size defined by textureSize when set,
484 or the item's size, multiplied by the window's device pixel ratio.
485
486 The function is called after the item has been filled with the fillColor.
487
488 Reimplement this function in a QQuickPaintedItem subclass to provide the
489 item's painting implementation, using \a painter.
490
491 \note The QML Scene Graph uses two separate threads, the main thread does
492 things such as processing events or updating animations while a second
493 thread does the actual issuing of graphics resource updates and the
494 recording of draw calls. As a consequence, paint() is not called from the
495 main GUI thread but from the GL enabled renderer thread. At the moment
496 paint() is called, the GUI thread is blocked and this is therefore
497 thread-safe.
498
499 \warning Extreme caution must be used when creating QObjects, emitting signals, starting
500 timers and similar inside this function as these will have affinity to the rendering thread.
501
502 \sa width(), height(), textureSize
503*/
504
505/*!
506 \reimp
507*/
508QSGNode *QQuickPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
509{
510 Q_UNUSED(data);
511 Q_D(QQuickPaintedItem);
512
513 if (width() <= 0 || height() <= 0) {
514 delete oldNode;
515 if (d->textureProvider) {
516 d->textureProvider->node = nullptr;
517 d->textureProvider->fireTextureChanged();
518 }
519 return nullptr;
520 }
521
522 QSGPainterNode *node = static_cast<QSGPainterNode *>(oldNode);
523 if (!node) {
524 node = d->sceneGraphContext()->createPainterNode(this);
525 d->node = node;
526 }
527
528 bool hasTextureSize = d->textureSize.width() > 0 && d->textureSize.height() > 0;
529
530 // Use the compat mode if any of the compat things are set and
531 // textureSize is 0x0.
532 if (!hasTextureSize
533 && (d->contentsScale != 1
534 || (d->contentsSize.width() > 0 && d->contentsSize.height() > 0))) {
535 QRectF br = contentsBoundingRect();
536 node->setContentsScale(d->contentsScale);
537 QSize size = QSize(qRound(br.width()), qRound(br.height()));
538 node->setSize(size);
539 node->setTextureSize(size);
540 } else {
541 // The default, use textureSize or item's size * device pixel ratio
542 node->setContentsScale(1);
543 QSize itemSize(qRound(width()), qRound(height()));
544 node->setSize(itemSize);
545 QSize textureSize = (hasTextureSize ? d->textureSize : itemSize)
546 * d->effectiveDevicePixelRatio();
547 node->setTextureSize(textureSize);
548 }
549
550 node->setPreferredRenderTarget(d->renderTarget);
551 node->setFastFBOResizing(d->performanceHints & FastFBOResizing);
552 node->setSmoothPainting(antialiasing());
553 node->setLinearFiltering(d->smooth);
554 node->setMipmapping(d->mipmap);
555 node->setOpaquePainting(d->opaquePainting);
556 node->setFillColor(d->fillColor);
557 node->setDirty(d->dirtyRect);
558 node->update();
559
560 d->dirtyRect = QRect();
561
562 if (d->textureProvider) {
563 d->textureProvider->node = node;
564 d->textureProvider->fireTextureChanged();
565 }
566
567 return node;
568}
569
570/*!
571 \reimp
572*/
573void QQuickPaintedItem::releaseResources()
574{
575 Q_D(QQuickPaintedItem);
576 if (d->textureProvider) {
577 QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
578 d->textureProvider = nullptr;
579 }
580 d->node = nullptr; // Managed by the scene graph, just clear the pointer.
581}
582
583void QQuickPaintedItem::invalidateSceneGraph()
584{
585 Q_D(QQuickPaintedItem);
586 delete d->textureProvider;
587 d->textureProvider = nullptr;
588 d->node = nullptr; // Managed by the scene graph, just clear the pointer
589}
590
591/*!
592 \reimp
593*/
594bool QQuickPaintedItem::isTextureProvider() const
595{
596 return true;
597}
598
599/*!
600 \reimp
601*/
602QSGTextureProvider *QQuickPaintedItem::textureProvider() const
603{
604 // When Item::layer::enabled == true, QQuickItem will be a texture
605 // provider. In this case we should prefer to return the layer rather
606 // than the image itself. The layer will include any children and any
607 // the image's wrap and fill mode.
608 if (QQuickItem::isTextureProvider())
609 return QQuickItem::textureProvider();
610
611 Q_D(const QQuickPaintedItem);
612 QQuickWindow *w = window();
613 if (!w || !w->isSceneGraphInitialized() || QThread::currentThread() != d->sceneGraphContext()->thread()) {
614 qWarning("QQuickPaintedItem::textureProvider: can only be queried on the rendering thread of an exposed window");
615 return nullptr;
616 }
617 if (!d->textureProvider)
618 d->textureProvider = new QQuickPaintedItemTextureProvider();
619 d->textureProvider->node = d->node;
620 return d->textureProvider;
621}
622
623
624/*!
625 \reimp
626*/
627void QQuickPaintedItem::itemChange(ItemChange change, const ItemChangeData &value)
628{
629 if (change == ItemDevicePixelRatioHasChanged)
630 update();
631 QQuickItem::itemChange(change, value);
632}
633
634QT_END_NAMESPACE
635
636#include "moc_qquickpainteditem.cpp"
QSGTexture * texture() const override
Returns a pointer to the texture object.