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
64QT_REQUIRE_CONFIG(graphicsview);
65
66QT_BEGIN_NAMESPACE
67
68class QGraphicsItemPrivate;
69
70#ifndef QDECLARATIVELISTPROPERTY
71#define QDECLARATIVELISTPROPERTY
72template<typename T>
73class QDeclarativeListProperty {
74public:
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
80 QDeclarativeListProperty()
81 : object(nullptr), data(nullptr), append(nullptr), count(nullptr), at(nullptr), clear(nullptr), dummy1(nullptr), dummy2(nullptr) {}
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 = nullptr, AtFunction t = nullptr,
86 ClearFunction r = nullptr)
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
111private:
112 static void qlist_append(QDeclarativeListProperty *p, T *v) {
113 ((QList<T *> *)p->data)->append(v);
114 }
115 static int qlist_count(QDeclarativeListProperty *p) {
116 return ((QList<T *> *)p->data)->count();
117 }
118 static T *qlist_at(QDeclarativeListProperty *p, int idx) {
119 return ((QList<T *> *)p->data)->at(idx);
120 }
121 static void qlist_clear(QDeclarativeListProperty *p) {
122 return ((QList<T *> *)p->data)->clear();
123 }
124};
125#endif
126
127class QGraphicsItemCache
128{
129public:
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 {
139 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 QList<QRectF> exposed;
148 bool allExposed;
149
150 // Empty cache
151 void purge();
152};
153
154class Q_WIDGETS_EXPORT QGraphicsItemPrivate
155{
156 Q_DECLARE_PUBLIC(QGraphicsItem)
157public:
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
178 static const QGraphicsItemPrivate *get(const QGraphicsItem *item)
179 {
180 return item->d_ptr.data();
181 }
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;
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;
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
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
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
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
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
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 {
292 ExtraStruct() { } // for QList, don't use
293 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 QList<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);
312 inline void ensureSceneTransform()
313 {
314 QGraphicsItem *that = q_func();
315 ensureSceneTransformRecursive(&that);
316 }
317
318 inline bool hasTranslateOnlySceneTransform()
319 {
320 ensureSceneTransform();
321 return sceneTransformTranslateOnly;
322 }
323
324 inline void invalidateChildrenSceneTransform()
325 {
326 for (int i = 0; i < children.size(); ++i)
327 children.at(i)->d_ptr->dirtySceneTransform = 1;
328 }
329
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
353 inline bool isOpacityNull() const
354 { return (opacity < qreal(0.001)); }
355
356 static inline bool isOpacityNull(qreal opacity)
357 { return (opacity < qreal(0.001)); }
358
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
369 inline qreal effectiveOpacity() const {
370 if (!parent || !opacity)
371 return opacity;
372
373 return calcEffectiveOpacity();
374 }
375
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
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
399 inline bool childrenClippedToShape() const
400 { return (flags & QGraphicsItem::ItemClipsChildrenToShape) || children.isEmpty(); }
401
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};
526Q_DECLARE_TYPEINFO(QGraphicsItemPrivate::ExtraStruct, Q_MOVABLE_TYPE);
527
528struct 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
538 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
571struct QGraphicsItemPaintInfo
572{
573 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)
594class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate
595{
596public:
597 QGraphicsItemEffectSourcePrivate(QGraphicsItem *i)
598 : QGraphicsEffectSourcePrivate(), item(i), info(nullptr)
599 {}
600
601 void detach() override
602 {
603 item->d_ptr->graphicsEffect = nullptr;
604 item->prepareGeometryChange();
605 }
606
607 const QGraphicsItem *graphicsItem() const override
608 { return item; }
609
610 const QWidget *widget() const override
611 { return nullptr; }
612
613 void update() override {
614 item->d_ptr->updateDueToGraphicsEffect = true;
615 item->update();
616 item->d_ptr->updateDueToGraphicsEffect = false;
617 }
618
619 void effectBoundingRectChanged() override
620 { item->prepareGeometryChange(); }
621
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
630 const QStyleOption *styleOption() const override
631 { return info ? info->option : nullptr; }
632
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*/
661inline 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*/
715inline bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2)
716{
717 return qt_closestItemFirst(item2, item1);
718}
719
720/*!
721 \internal
722*/
723inline 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*/
740inline 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*/
746inline QTransform QGraphicsItemPrivate::transformToParent() const
747{
748 QTransform matrix;
749 combineTransformToParent(&matrix);
750 return matrix;
751}
752
753/*!
754 \internal
755*/
756inline 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*/
776inline bool QGraphicsItemPrivate::insertionOrder(QGraphicsItem *a, QGraphicsItem *b)
777{
778 return a->d_ptr->siblingIndex < b->d_ptr->siblingIndex;
779}
780
781/*!
782 \internal
783*/
784inline 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
819QT_END_NAMESPACE
820
821#endif
822