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 |