Commit 0873b1e6 authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

DL: Ensure to force scoped updates to the local frame root.

This patch ensures that when forcing a layout we force it all the way
up to the local frame root, since the dimensions of the frame may have
an effect on the properties of the queried element.

R=chrishtr@chromium.org, rakina@chromium.org, szager@chromium.org

Change-Id: I9cfdb38560e9cd75a45d87d9749c92cac0016a61
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1695660Reviewed-by: default avatarStefan Zager <szager@chromium.org>
Commit-Queue: vmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676108}
parent b985cd0b
......@@ -15,6 +15,19 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
namespace blink {
namespace {
// Returns the frame owner node for the frame that contains the given child, if
// one exists. Returns nullptr otherwise.
const Node* GetFrameOwnerNode(const Node* child) {
if (!child || !child->GetDocument().GetFrame() ||
!child->GetDocument().GetFrame()->OwnerLayoutObject()) {
return nullptr;
}
return child->GetDocument().GetFrame()->OwnerLayoutObject()->GetNode();
}
} // namespace
bool DisplayLockUtilities::ActivateFindInPageMatchRangeIfNeeded(
const EphemeralRangeInFlatTree& range) {
......@@ -64,22 +77,28 @@ DisplayLockUtilities::ActivatableLockedInclusiveAncestors(Element& element) {
}
DisplayLockUtilities::ScopedChainForcedUpdate::ScopedChainForcedUpdate(
const Node* node) {
if (!RuntimeEnabledFeatures::DisplayLockingEnabled() ||
node->GetDocument().LockedDisplayLockCount() == 0) {
const Node* node,
bool include_self) {
if (!RuntimeEnabledFeatures::DisplayLockingEnabled())
return;
CreateParentFrameScopeIfNeeded(node);
if (node->GetDocument().LockedDisplayLockCount() == 0)
return;
}
const_cast<Node*>(node)->UpdateDistributionForFlatTreeTraversal();
// Get the right ancestor view. Only use inclusive ancestors if the node
// itself is locked and it prevents self layout. If self layout is not
// prevented, we don't need to force the subtree layout, so use exclusive
// ancestors in that case.
auto ancestor_view = [node] {
auto ancestor_view = [node, include_self] {
if (auto* element = DynamicTo<Element>(node)) {
auto* context = element->GetDisplayLockContext();
if (context && !context->ShouldLayout(DisplayLockContext::kSelf))
if (context &&
(include_self || !context->ShouldLayout(DisplayLockContext::kSelf))) {
return FlatTreeTraversal::InclusiveAncestorsOf(*node);
}
}
return FlatTreeTraversal::AncestorsOf(*node);
}();
......@@ -98,6 +117,15 @@ DisplayLockUtilities::ScopedChainForcedUpdate::ScopedChainForcedUpdate(
}
}
void DisplayLockUtilities::ScopedChainForcedUpdate::
CreateParentFrameScopeIfNeeded(const Node* node) {
auto* owner_node = GetFrameOwnerNode(node);
if (owner_node) {
parent_frame_scope_ =
std::make_unique<ScopedChainForcedUpdate>(owner_node, true);
}
}
const Element* DisplayLockUtilities::NearestLockedInclusiveAncestor(
const Node& node) {
auto* element = DynamicTo<Element>(node);
......@@ -187,26 +215,18 @@ bool DisplayLockUtilities::IsInLockedSubtreeCrossingFrames(
return true;
}
auto get_frame_owner_node = [](const Node* child) -> const Node* {
if (!child || !child->GetDocument().GetFrame() ||
!child->GetDocument().GetFrame()->OwnerLayoutObject()) {
return nullptr;
}
return child->GetDocument().GetFrame()->OwnerLayoutObject()->GetNode();
};
// Since we handled the self-check above, we need to do inclusive checks
// starting from the parent.
node = FlatTreeTraversal::Parent(*node);
// If we don't have a flat-tree parent, get the |source_node|'s owner node
// instead.
if (!node)
node = get_frame_owner_node(&source_node);
node = GetFrameOwnerNode(&source_node);
while (node) {
if (NearestLockedInclusiveAncestor(*node))
return true;
node = get_frame_owner_node(node);
node = GetFrameOwnerNode(node);
}
return false;
}
......
......@@ -18,17 +18,20 @@ class CORE_EXPORT DisplayLockUtilities {
public:
// This class forces updates on display locks from the given node up the
// ancestor chain until the root.
// ancestor chain until the local frame root.
class ScopedChainForcedUpdate {
STACK_ALLOCATED();
DISALLOW_COPY_AND_ASSIGN(ScopedChainForcedUpdate);
public:
explicit ScopedChainForcedUpdate(const Node* node);
explicit ScopedChainForcedUpdate(const Node* node,
bool include_self = false);
~ScopedChainForcedUpdate() = default;
void CreateParentFrameScopeIfNeeded(const Node* node);
private:
Vector<DisplayLockContext::ScopedForcedUpdate> scoped_update_forced_list_;
std::unique_ptr<ScopedChainForcedUpdate> parent_frame_scope_;
};
// Activates all the nodes within a find-in-page match |range|.
// Returns true if at least one node gets activated.
......
<!doctype HTML>
<html>
<meta charset="utf8">
<title>Display Locking: getBoundingClientRect on block layout</title>
<link rel="author" title="Rakina Zata Amni" href="mailto:rakina@chromium.org">
<link rel="help" href="https://github.com/WICG/display-locking">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
#container {
contain: style layout;
width: 123px;
height: 234px;
}
#frame {
padding: 0;
margin: 0;
width: 500px;
height: 500px;
}
</style>
<body>
<div id="container">
<iframe id="frame" frameborder=0 srcdoc='
<style>
body {
padding: 0;
margin: 0;
}
#target {
background: lightgreen;
width: 50%;
height: 50px;
}
</style>
<div id="target"></div>
'></iframe>
</div>
<script>
let load_promise = new Promise((resolve) => {
window.onload = resolve;
});
async_test(async(t) => {
await load_promise;
const container = document.getElementById("container");
await container.displayLock.acquire({ timeout: Infinity });
const frame = document.getElementById("frame");
frame.style.width = "224px";
frame.style.height = "248px";
const target = frame.contentDocument.getElementById("target");
t.step(() => assert_true(!!target, "sanity check that target exists"));
let rect = target.getBoundingClientRect();
t.step(() => assert_equals(rect.width, 112, "target uses update frame size for width"));
t.step(() => assert_equals(rect.height, 50, "target uses set size for height"));
t.done();
}, "getBoundingClientRect in iframe");
</script>
</body>
</html>
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