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