OLD | NEW |
| (Empty) |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef FindPaintOffsetAndVisualRectNeedingUpdate_h | |
6 #define FindPaintOffsetAndVisualRectNeedingUpdate_h | |
7 | |
8 #if DCHECK_IS_ON() | |
9 | |
10 #include "core/layout/LayoutObject.h" | |
11 #include "core/paint/FindPropertiesNeedingUpdate.h" | |
12 #include "core/paint/ObjectPaintInvalidator.h" | |
13 #include "core/paint/PaintInvalidator.h" | |
14 #include "core/paint/PaintLayer.h" | |
15 #include "core/paint/PaintPropertyTreeBuilder.h" | |
16 | |
17 namespace blink { | |
18 | |
19 // This file contains scope classes for catching cases where paint offset or | |
20 // visual rect needed an update but were not marked as such. If paint offset or | |
21 // any visual rect (including visual rect of the object itself, scroll controls, | |
22 // caret, selection, etc.) will change, the object must be marked as such by | |
23 // LayoutObject::setNeedsPaintOffsetAndVisualRectUpdate() (which is a private | |
24 // function called by several public paint-invalidation-flag setting functions). | |
25 | |
26 class FindPaintOffsetNeedingUpdateScope { | |
27 public: | |
28 FindPaintOffsetNeedingUpdateScope( | |
29 const LayoutObject& object, | |
30 const PaintPropertyTreeBuilderContext& context) | |
31 : m_object(object), | |
32 m_context(context), | |
33 m_oldPaintOffset(object.paintOffset()) { | |
34 if (object.paintProperties() && | |
35 object.paintProperties()->paintOffsetTranslation()) { | |
36 m_oldPaintOffsetTranslation = | |
37 object.paintProperties()->paintOffsetTranslation()->clone(); | |
38 } | |
39 } | |
40 | |
41 ~FindPaintOffsetNeedingUpdateScope() { | |
42 if (m_context.isActuallyNeeded) | |
43 return; | |
44 DCHECK_OBJECT_PROPERTY_EQ(m_object, &m_oldPaintOffset, | |
45 &m_object.paintOffset()); | |
46 const auto* paintOffsetTranslation = | |
47 m_object.paintProperties() | |
48 ? m_object.paintProperties()->paintOffsetTranslation() | |
49 : nullptr; | |
50 DCHECK_OBJECT_PROPERTY_EQ(m_object, m_oldPaintOffsetTranslation.get(), | |
51 paintOffsetTranslation); | |
52 } | |
53 | |
54 private: | |
55 const LayoutObject& m_object; | |
56 const PaintPropertyTreeBuilderContext& m_context; | |
57 LayoutPoint m_oldPaintOffset; | |
58 RefPtr<const TransformPaintPropertyNode> m_oldPaintOffsetTranslation; | |
59 }; | |
60 | |
61 class FindVisualRectNeedingUpdateScopeBase { | |
62 protected: | |
63 FindVisualRectNeedingUpdateScopeBase(const LayoutObject& object, | |
64 const PaintInvalidatorContext& context, | |
65 const LayoutRect& oldVisualRect) | |
66 : m_object(object), | |
67 m_context(context), | |
68 m_oldVisualRect(oldVisualRect), | |
69 m_neededVisualRectUpdate(context.needsVisualRectUpdate(object)) { | |
70 if (m_neededVisualRectUpdate) { | |
71 DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() || | |
72 (context.m_treeBuilderContext && | |
73 context.m_treeBuilderContext->isActuallyNeeded)); | |
74 return; | |
75 } | |
76 context.m_forceVisualRectUpdateForChecking = true; | |
77 DCHECK(context.needsVisualRectUpdate(object)); | |
78 } | |
79 | |
80 ~FindVisualRectNeedingUpdateScopeBase() { | |
81 m_context.m_forceVisualRectUpdateForChecking = false; | |
82 DCHECK_EQ(m_neededVisualRectUpdate, | |
83 m_context.needsVisualRectUpdate(m_object)); | |
84 } | |
85 | |
86 static LayoutRect inflatedRect(const LayoutRect& r) { | |
87 LayoutRect result = r; | |
88 result.inflate(1); | |
89 return result; | |
90 } | |
91 | |
92 void checkVisualRect(const LayoutRect& newVisualRect) { | |
93 if (m_neededVisualRectUpdate) | |
94 return; | |
95 DCHECK((m_oldVisualRect.isEmpty() && newVisualRect.isEmpty()) || | |
96 m_object.enclosingLayer()->subtreeIsInvisible() || | |
97 m_oldVisualRect == newVisualRect || | |
98 // The following check is to tolerate the differences caused by | |
99 // pixel snapping that may happen for one rect but not for another | |
100 // while we need neither paint invalidation nor raster invalidation | |
101 // for the change. This may miss some real subpixel changes of visual | |
102 // rects. TODO(wangxianzhu): Look into whether we can tighten this | |
103 // for SPv2. | |
104 inflatedRect(m_oldVisualRect).contains(newVisualRect) || | |
105 inflatedRect(newVisualRect).contains(m_oldVisualRect)) | |
106 << "Visual rect changed without needing update" | |
107 << " object=" << m_object.debugName() | |
108 << " old=" << m_oldVisualRect.toString() | |
109 << " new=" << newVisualRect.toString(); | |
110 } | |
111 | |
112 const LayoutObject& m_object; | |
113 const PaintInvalidatorContext& m_context; | |
114 LayoutRect m_oldVisualRect; | |
115 bool m_neededVisualRectUpdate; | |
116 }; | |
117 | |
118 // For updates of visual rects (e.g. of scroll controls, caret, selection,etc.) | |
119 // contained by an object. | |
120 class FindVisualRectNeedingUpdateScope : FindVisualRectNeedingUpdateScopeBase { | |
121 public: | |
122 FindVisualRectNeedingUpdateScope(const LayoutObject& object, | |
123 const PaintInvalidatorContext& context, | |
124 const LayoutRect& oldVisualRect, | |
125 // Must be a reference to a rect that | |
126 // outlives this scope. | |
127 const LayoutRect& newVisualRect) | |
128 : FindVisualRectNeedingUpdateScopeBase(object, context, oldVisualRect), | |
129 m_newVisualRectRef(newVisualRect) {} | |
130 | |
131 ~FindVisualRectNeedingUpdateScope() { checkVisualRect(m_newVisualRectRef); } | |
132 | |
133 private: | |
134 const LayoutRect& m_newVisualRectRef; | |
135 }; | |
136 | |
137 // For updates of object visual rect and location. | |
138 class FindObjectVisualRectNeedingUpdateScope | |
139 : FindVisualRectNeedingUpdateScopeBase { | |
140 public: | |
141 FindObjectVisualRectNeedingUpdateScope(const LayoutObject& object, | |
142 const PaintInvalidatorContext& context) | |
143 : FindVisualRectNeedingUpdateScopeBase(object, | |
144 context, | |
145 object.visualRect()), | |
146 m_oldLocation(ObjectPaintInvalidator(object).locationInBacking()) {} | |
147 | |
148 ~FindObjectVisualRectNeedingUpdateScope() { | |
149 checkVisualRect(m_object.visualRect()); | |
150 checkLocation(); | |
151 } | |
152 | |
153 void checkLocation() { | |
154 if (m_neededVisualRectUpdate) | |
155 return; | |
156 LayoutPoint newLocation = | |
157 ObjectPaintInvalidator(m_object).locationInBacking(); | |
158 // Location of LayoutText and non-root SVG is location of the visual rect | |
159 // which have been checked above. | |
160 DCHECK(m_object.isText() || m_object.isSVGChild() || | |
161 newLocation == m_oldLocation || | |
162 m_object.enclosingLayer()->subtreeIsInvisible() || | |
163 // See checkVisualRect for the issue of approximation. | |
164 LayoutRect(-1, -1, 2, 2) | |
165 .contains(LayoutRect(LayoutPoint(newLocation - m_oldLocation), | |
166 LayoutSize()))) | |
167 << "Location changed without needing update" | |
168 << " object=" << m_object.debugName() | |
169 << " old=" << m_oldLocation.toString() | |
170 << " new=" << newLocation.toString(); | |
171 } | |
172 | |
173 private: | |
174 LayoutPoint m_oldLocation; | |
175 }; | |
176 | |
177 } // namespace blink | |
178 | |
179 #endif // DCHECK_IS_ON() | |
180 | |
181 #endif // FindPaintOffsetAndVisualRectNeedingUpdate_h | |
OLD | NEW |