Commit 397a94c2 authored by Rakina Zata Amni's avatar Rakina Zata Amni Committed by Commit Bot

[Display Locking]: Unlock active find-in-page match

Activatable-locked subtrees are counted in total find-in-page matches,
but we currently still skip over them for active match navigation
(the specially-highlighted match). This CL makes us unlock/commit
relevant locked elements needed to show the active match (the ancestors
of the nodes in the active match range). This includes sending the
"beforeactivate" event to those elements.

Bug: 882663
Change-Id: I743faf1391ff0157fdca12a1cbba51fd29a680c9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1491069
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarFergal Daly <fergal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638467}
parent fad80abf
......@@ -1813,6 +1813,7 @@ jumbo_source_set("unit_tests") {
"css/threaded/text_renderer_threaded_test.cc",
"display_lock/display_lock_budget_test.cc",
"display_lock/display_lock_context_test.cc",
"display_lock/display_lock_utilities_test.cc",
"dom/attr_test.cc",
"dom/document_statistics_collector_test.cc",
"dom/document_test.cc",
......
......@@ -12,6 +12,8 @@ blink_core_sources("display_lock") {
"display_lock_budget.h",
"display_lock_context.cc",
"display_lock_context.h",
"display_lock_utilities.cc",
"display_lock_utilities.h",
"strict_yielding_display_lock_budget.cc",
"strict_yielding_display_lock_budget.h",
"unyielding_display_lock_budget.cc",
......
// 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.
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
#include "third_party/blink/renderer/core/dom/node.h"
#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"
namespace blink {
bool DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded(
const EphemeralRangeInFlatTree& range) {
if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
return false;
DCHECK(!range.IsNull());
DCHECK(!range.IsCollapsed());
if (range.GetDocument().LockedDisplayLockCount() ==
range.GetDocument().ActivationBlockingDisplayLockCount())
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
// block-level element which contains the match.
// This means we only need to traverse up from one node in the range, in this
// case we are traversing from the start position of the range.
Element* enclosing_block =
EnclosingBlock(range.StartPosition(), kCannotCrossEditingBoundary);
DCHECK(enclosing_block);
DCHECK_EQ(enclosing_block,
EnclosingBlock(range.EndPosition(), kCannotCrossEditingBoundary));
const HeapVector<Member<Element>>& elements_to_activate =
ActivatableLockedInclusiveAncestors(*enclosing_block);
for (Element* element : elements_to_activate) {
// We save the elements to a vector and go through & activate them one by
// one like this because the DOM structure might change due to running event
// handlers of the beforeactivate event.
element->ActivateDisplayLockIfNeeded();
}
return !elements_to_activate.IsEmpty();
}
const HeapVector<Member<Element>>
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(Element& element) {
HeapVector<Member<Element>> elements_to_activate;
for (Node& ancestor : FlatTreeTraversal::InclusiveAncestorsOf(element)) {
if (!ancestor.IsElementNode())
continue;
if (auto* context = ToElement(ancestor).GetDisplayLockContext()) {
DCHECK(context->IsActivatable());
if (!context->IsLocked())
continue;
elements_to_activate.push_back(&ToElement(ancestor));
}
}
return elements_to_activate;
}
} // namespace blink
// 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/editing/ephemeral_range.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
// Static utility class for display-locking related helpers.
class CORE_EXPORT DisplayLockUtilities {
STATIC_ONLY(DisplayLockUtilities);
public:
// 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);
// Returns activatable-locked inclusive ancestors of |element|.
// Note that this function will have failing DCHECKs if |element| is inside a
// non-activatable locked subtree (e.g. at least one ancestor is not
// activatable-locked).
static const HeapVector<Member<Element>> ActivatableLockedInclusiveAncestors(
Element& element);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_DISPLAY_LOCK_DISPLAY_LOCK_UTILITIES_H_
// 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.
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_options.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
class DisplayLockUtilitiesTest : public PageTestBase {
public:
void SetUp() override {
PageTestBase::SetUp(IntSize());
RuntimeEnabledFeatures::SetDisplayLockingEnabled(true);
}
void TearDown() override {
PageTestBase::TearDown();
RuntimeEnabledFeatures::SetDisplayLockingEnabled(false);
}
};
TEST_F(DisplayLockUtilitiesTest, ActivatableLockedInclusiveAncestors) {
SetBodyInnerHTML(R"HTML(
<style>
div {
contain: style layout;
}
</style>
<div id='outer'>
<div id='innerA'>
<div id='innermost'>text_node</div>
</div>
<div id='innerB'></div>
</div>
)HTML");
Element& outer = *GetDocument().getElementById("outer");
Element& inner_a = *GetDocument().getElementById("innerA");
Element& inner_b = *GetDocument().getElementById("innerB");
Element& innermost = *GetDocument().getElementById("innermost");
ShadowRoot& shadow_root =
inner_b.AttachShadowRootInternal(ShadowRootType::kOpen);
shadow_root.SetInnerHTMLFromString("<div id='shadowDiv'>shadow!</div>");
Element& shadow_div = *shadow_root.getElementById("shadowDiv");
auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame());
DisplayLockOptions options;
options.setActivatable(true);
// Lock outer with activatable flag.
{
ScriptState::Scope scope(script_state);
outer.getDisplayLockForBindings()->acquire(script_state, &options);
}
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 1);
EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
// Querying from every element gives |outer|.
HeapVector<Member<Element>> result_for_outer =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer);
EXPECT_EQ(result_for_outer.size(), 1u);
EXPECT_EQ(result_for_outer.at(0), outer);
HeapVector<Member<Element>> result_for_inner_a =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a);
EXPECT_EQ(result_for_inner_a.size(), 1u);
EXPECT_EQ(result_for_inner_a.at(0), outer);
HeapVector<Member<Element>> result_for_innermost =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost);
EXPECT_EQ(result_for_innermost.size(), 1u);
EXPECT_EQ(result_for_innermost.at(0), outer);
HeapVector<Member<Element>> result_for_inner_b =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b);
EXPECT_EQ(result_for_inner_b.size(), 1u);
EXPECT_EQ(result_for_inner_b.at(0), outer);
HeapVector<Member<Element>> result_for_shadow_div =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div);
EXPECT_EQ(result_for_shadow_div.size(), 1u);
EXPECT_EQ(result_for_shadow_div.at(0), outer);
// Lock innermost with activatable flag.
{
ScriptState::Scope scope(script_state);
innermost.getDisplayLockForBindings()->acquire(script_state, &options);
}
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 2);
EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
result_for_outer =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer);
EXPECT_EQ(result_for_outer.size(), 1u);
EXPECT_EQ(result_for_outer.at(0), outer);
result_for_inner_a =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a);
EXPECT_EQ(result_for_inner_a.size(), 1u);
EXPECT_EQ(result_for_inner_a.at(0), outer);
result_for_innermost =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost);
EXPECT_EQ(result_for_innermost.size(), 2u);
EXPECT_EQ(result_for_innermost.at(0), innermost);
EXPECT_EQ(result_for_innermost.at(1), outer);
result_for_inner_b =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b);
EXPECT_EQ(result_for_inner_b.size(), 1u);
EXPECT_EQ(result_for_inner_b.at(0), outer);
result_for_shadow_div =
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div);
EXPECT_EQ(result_for_shadow_div.size(), 1u);
EXPECT_EQ(result_for_shadow_div.at(0), outer);
// Unlock everything.
{
ScriptState::Scope scope(script_state);
innermost.getDisplayLockForBindings()->commit(script_state);
outer.getDisplayLockForBindings()->commit(script_state);
}
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(GetDocument().LockedDisplayLockCount(), 0);
EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
EXPECT_EQ(
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(outer).size(),
0u);
EXPECT_EQ(
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_a).size(),
0u);
EXPECT_EQ(DisplayLockUtilities::ActivatableLockedInclusiveAncestors(innermost)
.size(),
0u);
EXPECT_EQ(
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(inner_b).size(),
0u);
EXPECT_EQ(
DisplayLockUtilities::ActivatableLockedInclusiveAncestors(shadow_div)
.size(),
0u);
}
} // namespace blink
......@@ -37,6 +37,7 @@
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_view_client.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache_base.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/range.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/editor.h"
......@@ -74,9 +75,13 @@ void TextFinder::FindMatch::Trace(Visitor* visitor) {
static void ScrollToVisible(Range* match) {
const Node& first_node = *match->FirstNode();
if (RuntimeEnabledFeatures::InvisibleDOMEnabled() &&
InvisibleDOM::ActivateRangeIfNeeded(EphemeralRangeInFlatTree(match)))
if (RuntimeEnabledFeatures::InvisibleDOMEnabled() ||
RuntimeEnabledFeatures::DisplayLockingEnabled()) {
const EphemeralRangeInFlatTree range(match);
if (InvisibleDOM::ActivateRangeIfNeeded(range) ||
DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded(range))
first_node.GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
}
Settings* settings = first_node.GetDocument().GetSettings();
bool smooth_find_enabled =
settings ? settings->GetSmoothScrollForFindEnabled() : false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment