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 QtWidgets 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 #ifndef QGRAPHICSITEM_P_H
41 #define QGRAPHICSITEM_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists for the convenience
48 // of other Qt classes.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qgraphicsitem.h"
56 #include "qset.h"
57 #include "qpixmapcache.h"
58 #include <private/qgraphicsview_p.h>
59 #include "qgraphicstransform.h"
60 #include <private/qgraphicstransform_p.h>
61 
62 #include <QtCore/qpoint.h>
63 
64 QT_REQUIRE_CONFIG(graphicsview);
65 
66 QT_BEGIN_NAMESPACE
67 
68 class QGraphicsItemPrivate;
69 
70 #ifndef QDECLARATIVELISTPROPERTY
71 #define QDECLARATIVELISTPROPERTY
72 template<typename T>
73 class QDeclarativeListProperty {
74 public:
75     typedef void (*AppendFunction)(QDeclarativeListProperty<T> *, T*);
76     typedef int (*CountFunction)(QDeclarativeListProperty<T> *);
77     typedef T *(*AtFunction)(QDeclarativeListProperty<T> *, int);
78     typedef void (*ClearFunction)(QDeclarativeListProperty<T> *);
79 
QDeclarativeListProperty()80     QDeclarativeListProperty()
81         : object(nullptr), data(nullptr), append(nullptr), count(nullptr), at(nullptr), clear(nullptr), dummy1(nullptr), dummy2(nullptr) {}
QDeclarativeListProperty(QObject * o,QList<T * > & list)82     QDeclarativeListProperty(QObject *o, QList<T *> &list)
83         : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at),
84           clear(qlist_clear), dummy1(nullptr), dummy2(nullptr) {}
85     QDeclarativeListProperty(QObject *o, void *d, AppendFunction a, CountFunction c = 0, AtFunction t = 0,
86                     ClearFunction r = 0)
object(o)87         : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(nullptr), dummy2(nullptr) {}
88 
89     bool operator==(const QDeclarativeListProperty &o) const {
90         return object == o.object &&
91                data == o.data &&
92                append == o.append &&
93                count == o.count &&
94                at == o.at &&
95                clear == o.clear;
96     }
97 
98     QObject *object;
99     void *data;
100 
101     AppendFunction append;
102 
103     CountFunction count;
104     AtFunction at;
105 
106     ClearFunction clear;
107 
108     void *dummy1;
109     void *dummy2;
110 
111 private:
qlist_append(QDeclarativeListProperty * p,T * v)112     static void qlist_append(QDeclarativeListProperty *p, T *v) {
113         ((QList<T *> *)p->data)->append(v);
114     }
qlist_count(QDeclarativeListProperty * p)115     static int qlist_count(QDeclarativeListProperty *p) {
116         return ((QList<T *> *)p->data)->count();
117     }
qlist_at(QDeclarativeListProperty * p,int idx)118     static T *qlist_at(QDeclarativeListProperty *p, int idx) {
119         return ((QList<T *> *)p->data)->at(idx);
120     }
qlist_clear(QDeclarativeListProperty * p)121     static void qlist_clear(QDeclarativeListProperty *p) {
122         return ((QList<T *> *)p->data)->clear();
123     }
124 };
125 #endif
126 
127 class QGraphicsItemCache
128 {
129 public:
QGraphicsItemCache()130     QGraphicsItemCache() : allExposed(false) { }
131 
132     // ItemCoordinateCache only
133     QRect boundingRect;
134     QSize fixedSize;
135     QPixmapCache::Key key;
136 
137     // DeviceCoordinateCache only
138     struct DeviceData {
DeviceDataDeviceData139         DeviceData() {}
140         QTransform lastTransform;
141         QPoint cacheIndent;
142         QPixmapCache::Key key;
143     };
144     QHash<QPaintDevice *, DeviceData> deviceData;
145 
146     // List of logical exposed rects
147     QVector<QRectF> exposed;
148     bool allExposed;
149 
150     // Empty cache
151     void purge();
152 };
153 
154 class Q_WIDGETS_EXPORT QGraphicsItemPrivate
155 {
156     Q_DECLARE_PUBLIC(QGraphicsItem)
157 public:
158     enum Extra {
159         ExtraToolTip,
160         ExtraCursor,
161         ExtraCacheData,
162         ExtraMaxDeviceCoordCacheSize,
163         ExtraBoundingRegionGranularity
164     };
165 
166     enum AncestorFlag {
167         NoFlag = 0,
168         AncestorHandlesChildEvents = 0x1,
169         AncestorClipsChildren = 0x2,
170         AncestorIgnoresTransformations = 0x4,
171         AncestorFiltersChildEvents = 0x8,
172         AncestorContainsChildren = 0x10
173     };
174 
175     QGraphicsItemPrivate();
176     virtual ~QGraphicsItemPrivate();
177 
get(const QGraphicsItem * item)178     static const QGraphicsItemPrivate *get(const QGraphicsItem *item)
179     {
180         return item->d_ptr.data();
181     }
get(QGraphicsItem * item)182     static QGraphicsItemPrivate *get(QGraphicsItem *item)
183     {
184         return item->d_ptr.data();
185     }
186 
187     void updateChildWithGraphicsEffectFlagRecursively();
188     void updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,
189                             AncestorFlag flag = NoFlag, bool enabled = false, bool root = true);
190     void updateAncestorFlags();
191     void setIsMemberOfGroup(bool enabled);
192     void remapItemPos(QEvent *event, QGraphicsItem *item);
193     QTransform genericMapFromSceneTransform(const QWidget *viewport = nullptr) const;
194     QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const;
itemIsUntransformable()195     inline bool itemIsUntransformable() const
196     {
197         return (flags & QGraphicsItem::ItemIgnoresTransformations)
198             || (ancestorFlags & AncestorIgnoresTransformations);
199     }
200 
201     void combineTransformToParent(QTransform *x, const QTransform *viewTransform = nullptr) const;
202     void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = nullptr) const;
203     virtual void updateSceneTransformFromParent();
204 
205     static bool movableAncestorIsSelected(const QGraphicsItem *item);
206 
207     virtual void setPosHelper(const QPointF &pos);
208     void setTransformHelper(const QTransform &transform);
209     void prependGraphicsTransform(QGraphicsTransform *t);
210     void appendGraphicsTransform(QGraphicsTransform *t);
211     void setVisibleHelper(bool newVisible, bool explicitly, bool update = true,
212                           bool hiddenByPanel = false);
213     void setEnabledHelper(bool newEnabled, bool explicitly, bool update = true);
214     bool discardUpdateRequest(bool ignoreVisibleBit = false,
215                               bool ignoreDirtyBit = false, bool ignoreOpacity = false) const;
transformChanged()216     virtual void transformChanged() {}
217     int depth() const;
218 #if QT_CONFIG(graphicseffect)
219     enum InvalidateReason {
220         OpacityChanged
221     };
222     void invalidateParentGraphicsEffectsRecursively();
223     void invalidateChildGraphicsEffectsRecursively(InvalidateReason reason);
224 #endif // QT_CONFIG(graphicseffect)
225     void invalidateDepthRecursively();
226     void resolveDepth();
227     void addChild(QGraphicsItem *child);
228     void removeChild(QGraphicsItem *child);
229     QDeclarativeListProperty<QGraphicsObject> childrenList();
230     void setParentItemHelper(QGraphicsItem *parent, const QVariant *newParentVariant,
231                              const QVariant *thisPointerVariant);
232     void childrenBoundingRectHelper(QTransform *x, QRectF *rect, QGraphicsItem *topMostEffectItem);
233     void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
234                          const QRegion &exposedRegion, bool allItems = false) const;
235     QRectF effectiveBoundingRect(QGraphicsItem *topMostEffectItem = nullptr) const;
236     QRectF sceneEffectiveBoundingRect() const;
237 
238     QRectF effectiveBoundingRect(const QRectF &rect) const;
239 
resolveFont(uint inheritedMask)240     virtual void resolveFont(uint inheritedMask)
241     {
242         for (int i = 0; i < children.size(); ++i)
243             children.at(i)->d_ptr->resolveFont(inheritedMask);
244     }
245 
resolvePalette(uint inheritedMask)246     virtual void resolvePalette(uint inheritedMask)
247     {
248         for (int i = 0; i < children.size(); ++i)
249             children.at(i)->d_ptr->resolvePalette(inheritedMask);
250     }
251 
252     virtual bool isProxyWidget() const;
253 
extra(Extra type)254     inline QVariant extra(Extra type) const
255     {
256         for (int i = 0; i < extras.size(); ++i) {
257             const ExtraStruct &extra = extras.at(i);
258             if (extra.type == type)
259                 return extra.value;
260         }
261         return QVariant();
262     }
263 
setExtra(Extra type,const QVariant & value)264     inline void setExtra(Extra type, const QVariant &value)
265     {
266         int index = -1;
267         for (int i = 0; i < extras.size(); ++i) {
268             if (extras.at(i).type == type) {
269                 index = i;
270                 break;
271             }
272         }
273 
274         if (index == -1) {
275             extras << ExtraStruct(type, value);
276         } else {
277             extras[index].value = value;
278         }
279     }
280 
unsetExtra(Extra type)281     inline void unsetExtra(Extra type)
282     {
283         for (int i = 0; i < extras.size(); ++i) {
284             if (extras.at(i).type == type) {
285                 extras.removeAt(i);
286                 return;
287             }
288         }
289     }
290 
291     struct ExtraStruct {
ExtraStructExtraStruct292         ExtraStruct() {} // for QVector, don't use
ExtraStructExtraStruct293         ExtraStruct(Extra type, const QVariant &value)
294             : type(type), value(value)
295         { }
296 
297         Extra type;
298         QVariant value;
299 
300         bool operator<(Extra extra) const
301         { return type < extra; }
302     };
303 
304     QVector<ExtraStruct> extras;
305 
306     QGraphicsItemCache *maybeExtraItemCache() const;
307     QGraphicsItemCache *extraItemCache() const;
308     void removeExtraItemCache();
309 
310     void updatePaintedViewBoundingRects(bool updateChildren);
311     void ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem);
ensureSceneTransform()312     inline void ensureSceneTransform()
313     {
314         QGraphicsItem *that = q_func();
315         ensureSceneTransformRecursive(&that);
316     }
317 
hasTranslateOnlySceneTransform()318     inline bool hasTranslateOnlySceneTransform()
319     {
320         ensureSceneTransform();
321         return sceneTransformTranslateOnly;
322     }
323 
invalidateChildrenSceneTransform()324     inline void invalidateChildrenSceneTransform()
325     {
326         for (int i = 0; i < children.size(); ++i)
327             children.at(i)->d_ptr->dirtySceneTransform = 1;
328     }
329 
calcEffectiveOpacity()330     inline qreal calcEffectiveOpacity() const
331     {
332         qreal o = opacity;
333         QGraphicsItem *p = parent;
334         int myFlags = flags;
335         while (p) {
336             int parentFlags = p->d_ptr->flags;
337 
338             // If I have a parent, and I don't ignore my parent's opacity, and my
339             // parent propagates to me, then combine my local opacity with my parent's
340             // effective opacity into my effective opacity.
341             if ((myFlags & QGraphicsItem::ItemIgnoresParentOpacity)
342                 || (parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
343                 break;
344             }
345 
346             o *= p->d_ptr->opacity;
347             p = p->d_ptr->parent;
348             myFlags = parentFlags;
349         }
350         return o;
351     }
352 
isOpacityNull()353     inline bool isOpacityNull() const
354     { return (opacity < qreal(0.001)); }
355 
isOpacityNull(qreal opacity)356     static inline bool isOpacityNull(qreal opacity)
357     { return (opacity < qreal(0.001)); }
358 
isFullyTransparent()359     inline bool isFullyTransparent() const
360     {
361         if (isOpacityNull())
362             return true;
363         if (!parent)
364             return false;
365 
366         return isOpacityNull(calcEffectiveOpacity());
367     }
368 
effectiveOpacity()369     inline qreal effectiveOpacity() const {
370         if (!parent || !opacity)
371             return opacity;
372 
373         return calcEffectiveOpacity();
374     }
375 
combineOpacityFromParent(qreal parentOpacity)376     inline qreal combineOpacityFromParent(qreal parentOpacity) const
377     {
378         if (parent && !(flags & QGraphicsItem::ItemIgnoresParentOpacity)
379             && !(parent->d_ptr->flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
380             return parentOpacity * opacity;
381         }
382         return opacity;
383     }
384 
childrenCombineOpacity()385     inline bool childrenCombineOpacity() const
386     {
387         if (!children.size())
388             return true;
389         if (flags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)
390             return false;
391 
392         for (int i = 0; i < children.size(); ++i) {
393             if (children.at(i)->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)
394                 return false;
395         }
396         return true;
397     }
398 
childrenClippedToShape()399     inline bool childrenClippedToShape() const
400     { return (flags & QGraphicsItem::ItemClipsChildrenToShape) || children.isEmpty(); }
401 
isInvisible()402     inline bool isInvisible() const
403     {
404         return !visible || (childrenCombineOpacity() && isFullyTransparent());
405     }
406 
407     inline void markParentDirty(bool updateBoundingRect = false);
408 
409     void setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide);
410     void clearFocusHelper(bool giveFocusToParent, bool hiddenByParentPanel);
411     void setSubFocus(QGraphicsItem *rootItem = nullptr, QGraphicsItem *stopItem = nullptr);
412     void clearSubFocus(QGraphicsItem *rootItem = nullptr, QGraphicsItem *stopItem = nullptr);
413     void resetFocusProxy();
414     virtual void subFocusItemChange();
415     virtual void focusScopeItemChange(bool isSubFocusItem);
416 
417     static void children_append(QDeclarativeListProperty<QGraphicsObject> *list, QGraphicsObject *item);
418     static int children_count(QDeclarativeListProperty<QGraphicsObject> *list);
419     static QGraphicsObject *children_at(QDeclarativeListProperty<QGraphicsObject> *list, int);
420     static void children_clear(QDeclarativeListProperty<QGraphicsObject> *list);
421 
422     inline QTransform transformToParent() const;
423     inline void ensureSortedChildren();
424     static inline bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b);
425     void ensureSequentialSiblingIndex();
426     inline void sendScenePosChange();
427     virtual void siblingOrderChange();
428 
429     // Private Properties
430     virtual qreal width() const;
431     virtual void setWidth(qreal);
432     virtual void resetWidth();
433 
434     virtual qreal height() const;
435     virtual void setHeight(qreal);
436     virtual void resetHeight();
437 
438     QRectF childrenBoundingRect;
439     QRectF needsRepaint;
440     QHash<QWidget *, QRect> paintedViewBoundingRects;
441     QPointF pos;
442     qreal z;
443     qreal opacity;
444     QGraphicsScene *scene;
445     QGraphicsItem *parent;
446     QList<QGraphicsItem *> children;
447     struct TransformData;
448     TransformData *transformData;
449     QGraphicsEffect *graphicsEffect;
450     QTransform sceneTransform;
451     int index;
452     int siblingIndex;
453     int itemDepth;  // Lazily calculated when calling depth().
454     QGraphicsItem *focusProxy;
455     QList<QGraphicsItem **> focusProxyRefs;
456     QGraphicsItem *subFocusItem;
457     QGraphicsItem *focusScopeItem;
458     Qt::InputMethodHints imHints;
459     QGraphicsItem::PanelModality panelModality;
460 #ifndef QT_NO_GESTURES
461     QMap<Qt::GestureType, Qt::GestureFlags> gestureContext;
462 #endif
463 
464     // Packed 32 bits
465     quint32 acceptedMouseButtons : 5;
466     quint32 visible : 1;
467     quint32 explicitlyHidden : 1;
468     quint32 enabled : 1;
469     quint32 explicitlyDisabled : 1;
470     quint32 selected : 1;
471     quint32 acceptsHover : 1;
472     quint32 acceptDrops : 1;
473     quint32 isMemberOfGroup : 1;
474     quint32 handlesChildEvents : 1;
475     quint32 itemDiscovered : 1;
476     quint32 hasCursor : 1;
477     quint32 ancestorFlags : 5;
478     quint32 cacheMode : 2;
479     quint32 hasBoundingRegionGranularity : 1;
480     quint32 isWidget : 1;
481     quint32 dirty : 1;
482     quint32 dirtyChildren : 1;
483     quint32 localCollisionHack : 1;
484     quint32 inSetPosHelper : 1;
485     quint32 needSortChildren : 1;
486     quint32 allChildrenDirty : 1;
487     quint32 fullUpdatePending : 1;
488 
489     // Packed 32 bits
490     quint32 flags : 20;
491     quint32 paintedViewBoundingRectsNeedRepaint : 1;
492     quint32 dirtySceneTransform : 1;
493     quint32 geometryChanged : 1;
494     quint32 inDestructor : 1;
495     quint32 isObject : 1;
496     quint32 ignoreVisible : 1;
497     quint32 ignoreOpacity : 1;
498     quint32 acceptTouchEvents : 1;
499     quint32 acceptedTouchBeginEvent : 1;
500     quint32 filtersDescendantEvents : 1;
501     quint32 sceneTransformTranslateOnly : 1;
502     quint32 notifyBoundingRectChanged : 1;
503 #ifdef Q_OS_WASM
504     unsigned char :0; //this aligns 64bit field for wasm see QTBUG-65259
505 #endif
506     // New 32 bits
507     quint32 notifyInvalidated : 1;
508     quint32 mouseSetsFocus : 1;
509     quint32 explicitActivate : 1;
510     quint32 wantsActive : 1;
511     quint32 holesInSiblingIndex : 1;
512     quint32 sequentialOrdering : 1;
513     quint32 updateDueToGraphicsEffect : 1;
514     quint32 scenePosDescendants : 1;
515     quint32 pendingPolish : 1;
516     quint32 mayHaveChildWithGraphicsEffect : 1;
517     quint32 isDeclarativeItem : 1;
518     quint32 sendParentChangeNotification : 1;
519     quint32 dirtyChildrenBoundingRect : 1;
520     quint32 padding : 19;
521 
522     // Optional stacking order
523     int globalStackingOrder;
524     QGraphicsItem *q_ptr;
525 };
526 Q_DECLARE_TYPEINFO(QGraphicsItemPrivate::ExtraStruct, Q_MOVABLE_TYPE);
527 
528 struct QGraphicsItemPrivate::TransformData
529 {
530     QTransform transform;
531     qreal scale;
532     qreal rotation;
533     qreal xOrigin;
534     qreal yOrigin;
535     QList<QGraphicsTransform *> graphicsTransforms;
536     bool onlyTransform;
537 
TransformDataTransformData538     TransformData() :
539         scale(1.0), rotation(0.0),
540         xOrigin(0.0), yOrigin(0.0),
541         onlyTransform(true)
542     { }
543 
544     QTransform computedFullTransform(QTransform *postmultiplyTransform = nullptr) const
545     {
546         if (onlyTransform) {
547             if (!postmultiplyTransform || postmultiplyTransform->isIdentity())
548                 return transform;
549             if (transform.isIdentity())
550                 return *postmultiplyTransform;
551             return transform * *postmultiplyTransform;
552         }
553 
554         QTransform x(transform);
555         if (!graphicsTransforms.isEmpty()) {
556             QMatrix4x4 m;
557             for (int i = 0; i < graphicsTransforms.size(); ++i)
558                 graphicsTransforms.at(i)->applyTo(&m);
559             x *= m.toTransform();
560         }
561         x.translate(xOrigin, yOrigin);
562         x.rotate(rotation);
563         x.scale(scale, scale);
564         x.translate(-xOrigin, -yOrigin);
565         if (postmultiplyTransform)
566             x *= *postmultiplyTransform;
567         return x;
568     }
569 };
570 
571 struct QGraphicsItemPaintInfo
572 {
QGraphicsItemPaintInfoQGraphicsItemPaintInfo573     inline QGraphicsItemPaintInfo(const QTransform *const xform1, const QTransform *const xform2,
574                                   const QTransform *const xform3,
575                                   QRegion *r, QWidget *w, QStyleOptionGraphicsItem *opt,
576                                   QPainter *p, qreal o, bool b1, bool b2)
577         : viewTransform(xform1), transformPtr(xform2), effectTransform(xform3), exposedRegion(r), widget(w),
578           option(opt), painter(p), opacity(o), wasDirtySceneTransform(b1), drawItem(b2)
579     {}
580 
581     const QTransform *viewTransform;
582     const QTransform *transformPtr;
583     const QTransform *effectTransform;
584     QRegion *exposedRegion;
585     QWidget *widget;
586     QStyleOptionGraphicsItem *option;
587     QPainter *painter;
588     qreal opacity;
589     quint32 wasDirtySceneTransform : 1;
590     quint32 drawItem : 1;
591 };
592 
593 #if QT_CONFIG(graphicseffect)
594 class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate
595 {
596 public:
QGraphicsItemEffectSourcePrivate(QGraphicsItem * i)597     QGraphicsItemEffectSourcePrivate(QGraphicsItem *i)
598         : QGraphicsEffectSourcePrivate(), item(i), info(nullptr)
599     {}
600 
detach()601     void detach() override
602     {
603         item->d_ptr->graphicsEffect = nullptr;
604         item->prepareGeometryChange();
605     }
606 
graphicsItem()607     const QGraphicsItem *graphicsItem() const override
608     { return item; }
609 
widget()610     const QWidget *widget() const override
611     { return nullptr; }
612 
update()613     void update() override {
614         item->d_ptr->updateDueToGraphicsEffect = true;
615         item->update();
616         item->d_ptr->updateDueToGraphicsEffect = false;
617     }
618 
effectBoundingRectChanged()619     void effectBoundingRectChanged() override
620     { item->prepareGeometryChange(); }
621 
isPixmap()622     bool isPixmap() const override
623     {
624         return item->type() == QGraphicsPixmapItem::Type
625                && !(item->flags() & QGraphicsItem::ItemIsSelectable)
626                && item->d_ptr->children.size() == 0;
627             //|| (item->d_ptr->isObject && qobject_cast<QDeclarativeImage *>(q_func()));
628     }
629 
styleOption()630     const QStyleOption *styleOption() const override
631     { return info ? info->option : nullptr; }
632 
deviceRect()633     QRect deviceRect() const override
634     {
635         if (!info || !info->widget) {
636             qWarning("QGraphicsEffectSource::deviceRect: Not yet implemented, lacking device context");
637             return QRect();
638         }
639         return info->widget->rect();
640     }
641 
642     QRectF boundingRect(Qt::CoordinateSystem system) const override;
643     void draw(QPainter *) override;
644     QPixmap pixmap(Qt::CoordinateSystem system,
645                    QPoint *offset,
646                    QGraphicsEffect::PixmapPadMode mode) const override;
647     QRectF paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = nullptr) const;
648 
649     QGraphicsItem *item;
650     QGraphicsItemPaintInfo *info;
651     QTransform lastEffectTransform;
652 };
653 #endif // QT_CONFIG(graphicseffect)
654 
655 /*!
656     Returns \c true if \a item1 is on top of \a item2.
657     The items don't need to be siblings.
658 
659     \internal
660 */
qt_closestItemFirst(const QGraphicsItem * item1,const QGraphicsItem * item2)661 inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
662 {
663     // Siblings? Just check their z-values.
664     const QGraphicsItemPrivate *d1 = item1->d_ptr.data();
665     const QGraphicsItemPrivate *d2 = item2->d_ptr.data();
666     if (d1->parent == d2->parent)
667         return qt_closestLeaf(item1, item2);
668 
669     // Find common ancestor, and each item's ancestor closest to the common
670     // ancestor.
671     int item1Depth = d1->depth();
672     int item2Depth = d2->depth();
673     const QGraphicsItem *p = item1;
674     const QGraphicsItem *t1 = item1;
675     while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
676         if (p == item2) {
677             // item2 is one of item1's ancestors; item1 is on top
678             return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
679         }
680         t1 = p;
681         --item1Depth;
682     }
683     p = item2;
684     const QGraphicsItem *t2 = item2;
685     while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
686         if (p == item1) {
687             // item1 is one of item2's ancestors; item1 is not on top
688             return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
689         }
690         t2 = p;
691         --item2Depth;
692     }
693 
694     // item1Ancestor is now at the same level as item2Ancestor, but not the same.
695     const QGraphicsItem *p1 = t1;
696     const QGraphicsItem *p2 = t2;
697     while (t1 && t1 != t2) {
698         p1 = t1;
699         p2 = t2;
700         t1 = t1->d_ptr->parent;
701         t2 = t2->d_ptr->parent;
702     }
703 
704     // in case we have a common ancestor, we compare the immediate children in the ancestor's path.
705     // otherwise we compare the respective items' topLevelItems directly.
706     return qt_closestLeaf(p1, p2);
707 }
708 
709 /*!
710     Returns \c true if \a item2 is on top of \a item1.
711     The items don't need to be siblings.
712 
713     \internal
714 */
qt_closestItemLast(const QGraphicsItem * item1,const QGraphicsItem * item2)715 inline bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2)
716 {
717     return qt_closestItemFirst(item2, item1);
718 }
719 
720 /*!
721     \internal
722 */
qt_closestLeaf(const QGraphicsItem * item1,const QGraphicsItem * item2)723 inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
724 {
725     // Return true if sibling item1 is on top of item2.
726     const QGraphicsItemPrivate *d1 = item1->d_ptr.data();
727     const QGraphicsItemPrivate *d2 = item2->d_ptr.data();
728     bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
729     bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
730     if (f1 != f2)
731         return f2;
732     if (d1->z != d2->z)
733         return d1->z > d2->z;
734     return d1->siblingIndex > d2->siblingIndex;
735 }
736 
737 /*!
738     \internal
739 */
qt_notclosestLeaf(const QGraphicsItem * item1,const QGraphicsItem * item2)740 inline bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
741 { return qt_closestLeaf(item2, item1); }
742 
743 /*
744    return the full transform of the item to the parent.  This include the position and all the transform data
745 */
transformToParent()746 inline QTransform QGraphicsItemPrivate::transformToParent() const
747 {
748     QTransform matrix;
749     combineTransformToParent(&matrix);
750     return matrix;
751 }
752 
753 /*!
754     \internal
755 */
ensureSortedChildren()756 inline void QGraphicsItemPrivate::ensureSortedChildren()
757 {
758     if (needSortChildren) {
759         needSortChildren = 0;
760         sequentialOrdering = 1;
761         if (children.isEmpty())
762             return;
763         std::sort(children.begin(), children.end(), qt_notclosestLeaf);
764         for (int i = 0; i < children.size(); ++i) {
765             if (children.at(i)->d_ptr->siblingIndex != i) {
766                 sequentialOrdering = 0;
767                 break;
768             }
769         }
770     }
771 }
772 
773 /*!
774     \internal
775 */
insertionOrder(QGraphicsItem * a,QGraphicsItem * b)776 inline bool QGraphicsItemPrivate::insertionOrder(QGraphicsItem *a, QGraphicsItem *b)
777 {
778     return a->d_ptr->siblingIndex < b->d_ptr->siblingIndex;
779 }
780 
781 /*!
782     \internal
783 */
markParentDirty(bool updateBoundingRect)784 inline void QGraphicsItemPrivate::markParentDirty(bool updateBoundingRect)
785 {
786     QGraphicsItemPrivate *parentp = this;
787 #if QT_CONFIG(graphicseffect)
788     if (updateBoundingRect && parentp->graphicsEffect && !parentp->inSetPosHelper) {
789         parentp->notifyInvalidated = 1;
790         static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()
791                                                         ->source->d_func())->invalidateCache();
792     }
793 #endif
794     while (parentp->parent) {
795         parentp = parentp->parent->d_ptr.data();
796         parentp->dirtyChildren = 1;
797 
798         if (updateBoundingRect) {
799             parentp->dirtyChildrenBoundingRect = 1;
800             // ### Only do this if the parent's effect applies to the entire subtree.
801             parentp->notifyBoundingRectChanged = 1;
802         }
803 #if QT_CONFIG(graphicseffect)
804         if (parentp->graphicsEffect) {
805             if (updateBoundingRect) {
806                 static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()
807                                                                 ->source->d_func())->invalidateCache();
808                 parentp->notifyInvalidated = 1;
809             }
810             if (parentp->scene && parentp->graphicsEffect->isEnabled()) {
811                 parentp->dirty = 1;
812                 parentp->fullUpdatePending = 1;
813             }
814         }
815 #endif
816     }
817 }
818 
819 QT_END_NAMESPACE
820 
821 #endif
822