Chromium Code Reviews| 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..292dfe5d6b3376f30dd4a10230dc5203336d021e |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h |
| @@ -0,0 +1,177 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
|
pdr.
2017/03/27 21:15:02
Nice file, I like this.
|
| +// 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/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_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 || |
| + // See checkVisualRect for the issue of approximation. |
| + LayoutRect(-1, -1, 2, 2) |
| + .contains(LayoutPoint(newLocation - m_oldLocation))) |
| + << "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 |