| // Copyright 2019 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 THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_UTILITIES_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_UTILITIES_H_ |
| |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/display_lock/display_lock_context.h" |
| #include "third_party/blink/renderer/core/editing/ephemeral_range.h" |
| #include "third_party/blink/renderer/core/editing/frame_selection.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| |
| namespace blink { |
| |
| // Static utility class for display-locking related helpers. |
| class CORE_EXPORT DisplayLockUtilities { |
| STATIC_ONLY(DisplayLockUtilities); |
| |
| public: |
| // This class forces updates on display locks from the given node up the |
| // ancestor chain until the local frame root. |
| class CORE_EXPORT ScopedForcedUpdate { |
| DISALLOW_COPY_AND_ASSIGN(ScopedForcedUpdate); |
| STACK_ALLOCATED(); |
| |
| public: |
| ScopedForcedUpdate(ScopedForcedUpdate&& other) : impl_(other.impl_) { |
| other.impl_ = nullptr; |
| } |
| ~ScopedForcedUpdate() { |
| if (impl_) |
| impl_->Destroy(); |
| } |
| |
| ScopedForcedUpdate& operator=(ScopedForcedUpdate&& other) { |
| impl_ = other.impl_; |
| other.impl_ = nullptr; |
| return *this; |
| } |
| |
| private: |
| // It is important not to create multiple ScopedChainForcedUpdate scopes. |
| // The following functions update some combination of Style, Layout, Paint |
| // information after forcing the display locks. It should be enough to use |
| // one of the following functions instead of forcing the scope manually. |
| friend void Document::UpdateStyleAndLayoutForNode( |
| const Node* node, |
| DocumentUpdateReason reason); |
| friend void Document::UpdateStyleAndLayoutTreeForNode(const Node*); |
| friend void Document::UpdateStyleAndLayoutTreeForSubtree(const Node* node); |
| friend void Document::EnsurePaintLocationDataValidForNode( |
| const Node* node, |
| DocumentUpdateReason reason); |
| friend VisibleSelection |
| FrameSelection::ComputeVisibleSelectionInDOMTreeDeprecated() const; |
| |
| friend class DisplayLockContext; |
| |
| // Test friends. |
| friend class DisplayLockContextRenderingTest; |
| |
| explicit ScopedForcedUpdate(const Node* node, bool include_self = false) |
| : impl_(MakeGarbageCollected<Impl>(node, include_self)) {} |
| |
| friend class DisplayLockDocumentState; |
| |
| class CORE_EXPORT Impl final : public GarbageCollected<Impl> { |
| public: |
| explicit Impl(const Node* node, bool include_self = false); |
| |
| // Adds another display-lock scope to this chain. Added when a new lock is |
| // created in the ancestor chain of this chain's node. |
| void AddForcedUpdateScopeForContext(DisplayLockContext*); |
| |
| void Destroy(); |
| |
| void Trace(Visitor* visitor) const { |
| visitor->Trace(node_); |
| visitor->Trace(forced_context_set_); |
| visitor->Trace(parent_frame_impl_); |
| } |
| |
| private: |
| Member<const Node> node_; |
| HeapHashSet<Member<DisplayLockContext>> forced_context_set_; |
| Member<Impl> parent_frame_impl_; |
| }; |
| |
| Impl* impl_ = nullptr; |
| }; |
| |
| // Activates all the nodes within a find-in-page match |range|. |
| // Returns true if at least one node gets activated. |
| // See: http://bit.ly/2RXULVi, "beforeactivate Event" part. |
| static bool ActivateFindInPageMatchRangeIfNeeded( |
| const EphemeralRangeInFlatTree& range); |
| |
| // Activates all locked nodes in |range| that are activatable and doesn't |
| // have user-select:none. Returns true if we activated at least one node. |
| static bool ActivateSelectionRangeIfNeeded( |
| const EphemeralRangeInFlatTree& range); |
| |
| // Returns activatable-locked inclusive ancestors of |node|. |
| // Note that this function will return an empty list if |node| is inside a |
| // non-activatable locked subtree (e.g. at least one ancestor is not |
| // activatable-locked). |
| static const HeapVector<Member<Element>> ActivatableLockedInclusiveAncestors( |
| const Node& node, |
| DisplayLockActivationReason reason); |
| |
| // Returns the nearest inclusive ancestor of |node| that is display locked. |
| static const Element* NearestLockedInclusiveAncestor(const Node& node); |
| static Element* NearestLockedInclusiveAncestor(Node& node); |
| |
| // Returns the nearest inclusive ancestor of |element| that has |
| // content-visibility: hidden-matchable. |
| static Element* NearestHiddenMatchableInclusiveAncestor(Element& element); |
| |
| // Returns the nearest non-inclusive ancestor of |node| that is display |
| // locked. |
| static Element* NearestLockedExclusiveAncestor(const Node& node); |
| |
| // Returns the highest exclusive ancestor of |node| that is display locked. |
| // Note that this function crosses local frames. |
| static Element* HighestLockedExclusiveAncestor(const Node& node); |
| static Element* HighestLockedInclusiveAncestor(const Node& node); |
| |
| // LayoutObject versions of the NearestLocked* ancestor functions. |
| static Element* NearestLockedInclusiveAncestor(const LayoutObject& object); |
| static Element* NearestLockedExclusiveAncestor(const LayoutObject& object); |
| |
| // Returns the nearest ancestor element which has a lock that prevents |
| // prepaint. Note that this is different from a nearest locked ancestor since |
| // the prepaint update can be forced. |
| static Element* LockedAncestorPreventingPrePaint(const LayoutObject& object); |
| |
| // Returns the nearest ancestor element which has a lock that prevents |
| // layout. Note that this is different from a nearest locked ancestor since |
| // the layout update can be forced. |
| static Element* LockedAncestorPreventingLayout(const LayoutObject& object); |
| |
| // Returns the nearest ancestor element which has a lock that prevents |
| // style. Note that this is different from a nearest locked ancestor since |
| // the style update can be forced. |
| static Element* LockedAncestorPreventingStyle(const Node& element); |
| |
| // Returns true if |node| is not in a locked subtree, or if it's possible to |
| // activate all of the locked ancestors for |activation_reason|. |
| static bool IsInUnlockedOrActivatableSubtree( |
| const Node& node, |
| DisplayLockActivationReason activation_reason = |
| DisplayLockActivationReason::kAny); |
| |
| // Returns true if |node| is in a locked subtree, and at least one of its |
| // locked ancestors can't be activated with |activation_reason|. In other |
| // words, this node should be treated as if it's not in the tree for |
| // |activation_reason|. |
| static bool ShouldIgnoreNodeDueToDisplayLock( |
| const Node& node, |
| DisplayLockActivationReason activation_reason) { |
| return !IsInUnlockedOrActivatableSubtree(node, activation_reason); |
| } |
| |
| // Returns true if the element is in a locked subtree (or is self-locked with |
| // no self-updates). This crosses frames while navigating the ancestor chain. |
| static bool IsInLockedSubtreeCrossingFrames(const Node& node); |
| |
| // Called when the focused element changes. These functions update locks to |
| // ensure that focused element ancestors remain unlocked for 'auto' state. |
| static void ElementLostFocus(Element*); |
| static void ElementGainedFocus(Element*); |
| |
| static void SelectionChanged(const EphemeralRangeInFlatTree& old_selection, |
| const EphemeralRangeInFlatTree& new_selection); |
| static void SelectionRemovedFromDocument(Document& document); |
| |
| static bool PrePaintBlockedInParentFrame(LayoutView* layout_view); |
| |
| static bool IsAutoWithoutLayout(const LayoutObject& object); |
| |
| private: |
| static bool UpdateStyleAndLayoutForRangeIfNeeded( |
| const EphemeralRangeInFlatTree& range, |
| DisplayLockActivationReason reason); |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_UTILITIES_H_ |