blob: 022ac073ca6eb92023014933f2f1d12d774f8a30 [file] [log] [blame]
// 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_