diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc | 176 |
1 files changed, 143 insertions, 33 deletions
diff --git a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc index 81ff80d17e2..183b36b0f3c 100644 --- a/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc +++ b/chromium/third_party/blink/renderer/core/display_lock/display_lock_utilities.cc @@ -12,9 +12,12 @@ #include "third_party/blink/renderer/core/dom/text.h" #include "third_party/blink/renderer/core/editing/editing_boundary.h" #include "third_party/blink/renderer/core/editing/editing_utilities.h" +#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" #include "third_party/blink/renderer/core/layout/layout_view.h" +#include <set> + namespace blink { namespace { @@ -32,9 +35,9 @@ bool UpdateStyleAndLayoutForRangeIfNeeded(const EphemeralRangeInFlatTree& range, DisplayLockActivationReason reason) { if (range.IsNull() || range.IsCollapsed()) return false; - if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&range.GetDocument()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || range.GetDocument().LockedDisplayLockCount() == - range.GetDocument().ActivationBlockingDisplayLockCount()) + range.GetDocument().DisplayLockBlockingAllActivationCount()) return false; Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_; for (Node& node : range.Nodes()) { @@ -50,21 +53,35 @@ bool UpdateStyleAndLayoutForRangeIfNeeded(const EphemeralRangeInFlatTree& range, ->GetScopedForcedUpdate()); } } - if (!scoped_forced_update_list_.IsEmpty()) - range.GetDocument().UpdateStyleAndLayout(); + if (!scoped_forced_update_list_.IsEmpty()) { + range.GetDocument().UpdateStyleAndLayout( + DocumentUpdateReason::kDisplayLock); + } return !scoped_forced_update_list_.IsEmpty(); } +void PopulateAncestorContexts(Node* node, + std::set<DisplayLockContext*>* contexts) { + DCHECK(node); + for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(*node)) { + auto* ancestor_element = DynamicTo<Element>(ancestor); + if (!ancestor_element) + continue; + if (auto* context = ancestor_element->GetDisplayLockContext()) + contexts->insert(context); + } +} + } // namespace bool DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded( const EphemeralRangeInFlatTree& range) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&range.GetDocument())) + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled()) return false; DCHECK(!range.IsNull()); DCHECK(!range.IsCollapsed()); if (range.GetDocument().LockedDisplayLockCount() == - range.GetDocument().ActivationBlockingDisplayLockCount()) + range.GetDocument().DisplayLockBlockingAllActivationCount()) return false; // Find-in-page matches can't span multiple block-level elements (because the // text will be broken by newlines between blocks), so first we find the @@ -73,9 +90,13 @@ bool DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded( // case we are traversing from the start position of the range. Element* enclosing_block = EnclosingBlock(range.StartPosition(), kCannotCrossEditingBoundary); + // Note that we don't check the `range.EndPosition()` since we just activate + // the beginning of the range. In find-in-page cases, the end position is the + // same since the matches cannot cross block boundaries. However, in + // scroll-to-text, the range might be different, but we still just activate + // the beginning of the range. See + // https://github.com/WICG/display-locking/issues/125 for more details. DCHECK(enclosing_block); - DCHECK_EQ(enclosing_block, - EnclosingBlock(range.EndPosition(), kCannotCrossEditingBoundary)); return enclosing_block->ActivateDisplayLockIfNeeded( DisplayLockActivationReason::kFindInPage); } @@ -84,9 +105,9 @@ bool DisplayLockUtilities::ActivateSelectionRangeIfNeeded( const EphemeralRangeInFlatTree& range) { if (range.IsNull() || range.IsCollapsed()) return false; - if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&range.GetDocument()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || range.GetDocument().LockedDisplayLockCount() == - range.GetDocument().ActivationBlockingDisplayLockCount()) + range.GetDocument().DisplayLockBlockingAllActivationCount()) return false; UpdateStyleAndLayoutForRangeIfNeeded(range, DisplayLockActivationReason::kSelection); @@ -112,10 +133,9 @@ DisplayLockUtilities::ActivatableLockedInclusiveAncestors( DisplayLockActivationReason reason) { HeapVector<Member<Element>> elements_to_activate; const_cast<Node*>(&node)->UpdateDistributionForFlatTreeTraversal(); - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node.GetExecutionContext()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || node.GetDocument().LockedDisplayLockCount() == - node.GetDocument().ActivationBlockingDisplayLockCount()) + node.GetDocument().DisplayLockBlockingAllActivationCount()) return elements_to_activate; for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(node)) { @@ -140,8 +160,7 @@ DisplayLockUtilities::ActivatableLockedInclusiveAncestors( DisplayLockUtilities::ScopedChainForcedUpdate::ScopedChainForcedUpdate( const Node* node, bool include_self) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node->GetExecutionContext())) + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled()) return; CreateParentFrameScopeIfNeeded(node); @@ -197,8 +216,7 @@ const Element* DisplayLockUtilities::NearestLockedInclusiveAncestor( auto* element = DynamicTo<Element>(node); if (!element) return NearestLockedExclusiveAncestor(node); - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node.GetExecutionContext()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || !node.isConnected() || node.GetDocument().LockedDisplayLockCount() == 0 || !node.CanParticipateInFlatTree()) { return nullptr; @@ -217,8 +235,7 @@ Element* DisplayLockUtilities::NearestLockedInclusiveAncestor(Node& node) { Element* DisplayLockUtilities::NearestLockedExclusiveAncestor( const Node& node) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node.GetExecutionContext()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || !node.isConnected() || node.GetDocument().LockedDisplayLockCount() == 0 || !node.CanParticipateInFlatTree()) { return nullptr; @@ -240,8 +257,7 @@ Element* DisplayLockUtilities::NearestLockedExclusiveAncestor( Element* DisplayLockUtilities::HighestLockedInclusiveAncestor( const Node& node) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node.GetExecutionContext()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || node.GetDocument().LockedDisplayLockCount() == 0 || !node.CanParticipateInFlatTree()) { return nullptr; @@ -262,8 +278,7 @@ Element* DisplayLockUtilities::HighestLockedInclusiveAncestor( Element* DisplayLockUtilities::HighestLockedExclusiveAncestor( const Node& node) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - node.GetExecutionContext()) || + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || node.GetDocument().LockedDisplayLockCount() == 0 || !node.CanParticipateInFlatTree()) { return nullptr; @@ -296,29 +311,29 @@ Element* DisplayLockUtilities::NearestLockedExclusiveAncestor( return nullptr; } -bool DisplayLockUtilities::IsInNonActivatableLockedSubtree(const Node& node) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( +bool DisplayLockUtilities::IsInUnlockedOrActivatableSubtree( + const Node& node, + DisplayLockActivationReason activation_reason) { + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled( node.GetExecutionContext()) || node.GetDocument().LockedDisplayLockCount() == 0 || - node.GetDocument().ActivationBlockingDisplayLockCount() == 0 || + node.GetDocument().DisplayLockBlockingAllActivationCount() == 0 || !node.CanParticipateInFlatTree()) { - return false; + return true; } for (auto* element = NearestLockedExclusiveAncestor(node); element; element = NearestLockedExclusiveAncestor(*element)) { - if (!element->GetDisplayLockContext()->IsActivatable( - DisplayLockActivationReason::kAny)) { - return true; + if (!element->GetDisplayLockContext()->IsActivatable(activation_reason)) { + return false; } } - return false; + return true; } bool DisplayLockUtilities::IsInLockedSubtreeCrossingFrames( const Node& source_node) { - if (!RuntimeEnabledFeatures::DisplayLockingEnabled( - source_node.GetExecutionContext())) + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled()) return false; const Node* node = &source_node; @@ -347,4 +362,99 @@ bool DisplayLockUtilities::IsInLockedSubtreeCrossingFrames( return false; } +void DisplayLockUtilities::ElementLostFocus(Element* element) { + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || + (element && element->GetDocument().DisplayLockCount() == 0)) + return; + for (; element; element = FlatTreeTraversal::ParentElement(*element)) { + auto* context = element->GetDisplayLockContext(); + if (context) + context->NotifySubtreeLostFocus(); + } +} +void DisplayLockUtilities::ElementGainedFocus(Element* element) { + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || + (element && element->GetDocument().DisplayLockCount() == 0)) + return; + + for (; element; element = FlatTreeTraversal::ParentElement(*element)) { + auto* context = element->GetDisplayLockContext(); + if (context) + context->NotifySubtreeGainedFocus(); + } +} + +void DisplayLockUtilities::SelectionChanged( + const EphemeralRangeInFlatTree& old_selection, + const EphemeralRangeInFlatTree& new_selection) { + if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() || + (!old_selection.IsNull() && + old_selection.GetDocument().DisplayLockCount() == 0) || + (!new_selection.IsNull() && + new_selection.GetDocument().DisplayLockCount() == 0)) + return; + + TRACE_EVENT0("blink", "DisplayLockUtilities::SelectionChanged"); + std::set<Node*> old_nodes; + for (Node& node : old_selection.Nodes()) + old_nodes.insert(&node); + + std::set<Node*> new_nodes; + for (Node& node : new_selection.Nodes()) + new_nodes.insert(&node); + + std::set<DisplayLockContext*> lost_selection_contexts; + std::set<DisplayLockContext*> gained_selection_contexts; + + // Skip common nodes and extract contexts from nodes that lost selection and + // contexts from nodes that gained selection. + // This is similar to std::set_symmetric_difference except that we need to + // know which set the resulting item came from. In this version, we simply do + // the relevant operation on each of the items instead of storing the + // difference. + std::set<Node*>::iterator old_it = old_nodes.begin(); + std::set<Node*>::iterator new_it = new_nodes.begin(); + while (old_it != old_nodes.end() && new_it != new_nodes.end()) { + // Compare the addresses since that's how the nodes are ordered in the set. + if (*old_it < *new_it) { + PopulateAncestorContexts(*old_it++, &lost_selection_contexts); + } else if (*old_it > *new_it) { + PopulateAncestorContexts(*new_it++, &gained_selection_contexts); + } else { + ++old_it; + ++new_it; + } + } + while (old_it != old_nodes.end()) + PopulateAncestorContexts(*old_it++, &lost_selection_contexts); + while (new_it != new_nodes.end()) + PopulateAncestorContexts(*new_it++, &gained_selection_contexts); + + // Now do a similar thing with contexts: skip common ones, and mark the ones + // that lost selection or gained selection as such. + std::set<DisplayLockContext*>::iterator lost_it = + lost_selection_contexts.begin(); + std::set<DisplayLockContext*>::iterator gained_it = + gained_selection_contexts.begin(); + while (lost_it != lost_selection_contexts.end() && + gained_it != gained_selection_contexts.end()) { + if (*lost_it < *gained_it) { + (*lost_it++)->NotifySubtreeLostSelection(); + } else if (*lost_it > *gained_it) { + (*gained_it++)->NotifySubtreeGainedSelection(); + } else { + ++lost_it; + ++gained_it; + } + } + while (lost_it != lost_selection_contexts.end()) + (*lost_it++)->NotifySubtreeLostSelection(); + while (gained_it != gained_selection_contexts.end()) + (*gained_it++)->NotifySubtreeGainedSelection(); +} + +void DisplayLockUtilities::SelectionRemovedFromDocument(Document& document) { + document.NotifySelectionRemovedFromDisplayLocks(); +} + } // namespace blink |