Index: third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h |
diff --git a/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h b/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..711bd68ba5e372168c2a953a14bc57bac4f20224 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h |
@@ -0,0 +1,181 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef FindPaintOffsetAndVisualRectNeedingUpdate_h |
+#define FindPaintOffsetAndVisualRectNeedingUpdate_h |
+ |
+#if DCHECK_IS_ON() |
+ |
+#include "core/layout/LayoutObject.h" |
+#include "core/paint/FindPropertiesNeedingUpdate.h" |
+#include "core/paint/ObjectPaintInvalidator.h" |
+#include "core/paint/PaintInvalidator.h" |
+#include "core/paint/PaintLayer.h" |
+#include "core/paint/PaintPropertyTreeBuilder.h" |
+ |
+namespace blink { |
+ |
+// This file contains scope classes for catching cases where paint offset or |
+// visual rect needed an update but were not marked as such. If paint offset or |
+// any visual rect (including visual rect of the object itself, scroll controls, |
+// caret, selection, etc.) will change, the object must be marked as such by |
+// LayoutObject::setNeedsPaintOffsetAndVisualRectUpdate() (which is a private |
+// function called by several public paint-invalidation-flag setting functions). |
+ |
+class FindPaintOffsetNeedingUpdateScope { |
+ public: |
+ FindPaintOffsetNeedingUpdateScope( |
+ const LayoutObject& object, |
+ const PaintPropertyTreeBuilderContext& context) |
+ : m_object(object), |
+ m_context(context), |
+ m_oldPaintOffset(object.paintOffset()) { |
+ if (object.paintProperties() && |
+ object.paintProperties()->paintOffsetTranslation()) { |
+ m_oldPaintOffsetTranslation = |
+ object.paintProperties()->paintOffsetTranslation()->clone(); |
+ } |
+ } |
+ |
+ ~FindPaintOffsetNeedingUpdateScope() { |
+ if (m_context.isActuallyNeeded) |
+ return; |
+ DCHECK_OBJECT_PROPERTY_EQ(m_object, &m_oldPaintOffset, |
+ &m_object.paintOffset()); |
+ const auto* paintOffsetTranslation = |
+ m_object.paintProperties() |
+ ? m_object.paintProperties()->paintOffsetTranslation() |
+ : nullptr; |
+ DCHECK_OBJECT_PROPERTY_EQ(m_object, m_oldPaintOffsetTranslation.get(), |
+ paintOffsetTranslation); |
+ } |
+ |
+ private: |
+ const LayoutObject& m_object; |
+ const PaintPropertyTreeBuilderContext& m_context; |
+ LayoutPoint m_oldPaintOffset; |
+ RefPtr<const TransformPaintPropertyNode> m_oldPaintOffsetTranslation; |
+}; |
+ |
+class FindVisualRectNeedingUpdateScopeBase { |
+ protected: |
+ FindVisualRectNeedingUpdateScopeBase(const LayoutObject& object, |
+ const PaintInvalidatorContext& context, |
+ const LayoutRect& oldVisualRect) |
+ : m_object(object), |
+ m_context(context), |
+ m_oldVisualRect(oldVisualRect), |
+ m_neededVisualRectUpdate(context.needsVisualRectUpdate(object)) { |
+ if (m_neededVisualRectUpdate) { |
+ DCHECK(!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() || |
+ (context.m_treeBuilderContext && |
+ context.m_treeBuilderContext->isActuallyNeeded)); |
+ return; |
+ } |
+ context.m_forceVisualRectUpdateForChecking = true; |
+ DCHECK(context.needsVisualRectUpdate(object)); |
+ } |
+ |
+ ~FindVisualRectNeedingUpdateScopeBase() { |
+ m_context.m_forceVisualRectUpdateForChecking = false; |
+ DCHECK_EQ(m_neededVisualRectUpdate, |
+ m_context.needsVisualRectUpdate(m_object)); |
+ } |
+ |
+ static LayoutRect inflatedRect(const LayoutRect& r) { |
+ LayoutRect result = r; |
+ result.inflate(1); |
+ return result; |
+ } |
+ |
+ void checkVisualRect(const LayoutRect& newVisualRect) { |
+ if (m_neededVisualRectUpdate) |
+ return; |
+ DCHECK((m_oldVisualRect.isEmpty() && newVisualRect.isEmpty()) || |
+ m_object.enclosingLayer()->subtreeIsInvisible() || |
+ m_oldVisualRect == newVisualRect || |
+ // The following check is to tolerate the differences caused by |
+ // pixel snapping that may happen for one rect but not for another |
+ // while we need neither paint invalidation nor raster invalidation |
+ // for the change. This may miss some real subpixel changes of visual |
+ // rects. TODO(wangxianzhu): Look into whether we can tighten this |
+ // for SPv2. |
+ inflatedRect(m_oldVisualRect).contains(newVisualRect) || |
+ inflatedRect(newVisualRect).contains(m_oldVisualRect)) |
+ << "Visual rect changed without needing update" |
+ << " object=" << m_object.debugName() |
+ << " old=" << m_oldVisualRect.toString() |
+ << " new=" << newVisualRect.toString(); |
+ } |
+ |
+ const LayoutObject& m_object; |
+ const PaintInvalidatorContext& m_context; |
+ LayoutRect m_oldVisualRect; |
+ bool m_neededVisualRectUpdate; |
+}; |
+ |
+// For updates of visual rects (e.g. of scroll controls, caret, selection,etc.) |
+// contained by an object. |
+class FindVisualRectNeedingUpdateScope : FindVisualRectNeedingUpdateScopeBase { |
+ public: |
+ FindVisualRectNeedingUpdateScope(const LayoutObject& object, |
+ const PaintInvalidatorContext& context, |
+ const LayoutRect& oldVisualRect, |
+ // Must be a reference to a rect that |
+ // outlives this scope. |
+ const LayoutRect& newVisualRect) |
+ : FindVisualRectNeedingUpdateScopeBase(object, context, oldVisualRect), |
+ m_newVisualRectRef(newVisualRect) {} |
+ |
+ ~FindVisualRectNeedingUpdateScope() { checkVisualRect(m_newVisualRectRef); } |
+ |
+ private: |
+ const LayoutRect& m_newVisualRectRef; |
+}; |
+ |
+// For updates of object visual rect and location. |
+class FindObjectVisualRectNeedingUpdateScope |
+ : FindVisualRectNeedingUpdateScopeBase { |
+ public: |
+ FindObjectVisualRectNeedingUpdateScope(const LayoutObject& object, |
+ const PaintInvalidatorContext& context) |
+ : FindVisualRectNeedingUpdateScopeBase(object, |
+ context, |
+ object.visualRect()), |
+ m_oldLocation(ObjectPaintInvalidator(object).locationInBacking()) {} |
+ |
+ ~FindObjectVisualRectNeedingUpdateScope() { |
+ checkVisualRect(m_object.visualRect()); |
+ checkLocation(); |
+ } |
+ |
+ void checkLocation() { |
+ if (m_neededVisualRectUpdate) |
+ return; |
+ LayoutPoint newLocation = |
+ ObjectPaintInvalidator(m_object).locationInBacking(); |
+ // Location of LayoutText and non-root SVG is location of the visual rect |
+ // which have been checked above. |
+ DCHECK(m_object.isText() || m_object.isSVGChild() || |
+ newLocation == m_oldLocation || |
+ m_object.enclosingLayer()->subtreeIsInvisible() || |
+ // See checkVisualRect for the issue of approximation. |
+ LayoutRect(-1, -1, 2, 2) |
+ .contains(LayoutRect(LayoutPoint(newLocation - m_oldLocation), |
+ LayoutSize()))) |
+ << "Location changed without needing update" |
+ << " object=" << m_object.debugName() |
+ << " old=" << m_oldLocation.toString() |
+ << " new=" << newLocation.toString(); |
+ } |
+ |
+ private: |
+ LayoutPoint m_oldLocation; |
+}; |
+ |
+} // namespace blink |
+ |
+#endif // DCHECK_IS_ON() |
+ |
+#endif // FindPaintOffsetAndVisualRectNeedingUpdate_h |