Commit 6fb0fe3f authored by David Bokan's avatar David Bokan Committed by Commit Bot

[Reland] Make touch handles relative to scrolling contents

Selection bounds are sent from Blink to CC as part of a commit cycle so
that we can draw touch handles for it. Currently, the selection bounds
are relative to the main graphics layer of a CompositedLayerMapping. In
the case of a scroller, this will be its clip rect - rather than its
scrolling contents layer. Unfortunately, this means that scrolling on
the compositor isn't applied as part of the ToScreen transformation on
the selection bounds so scrolling wont update the selection bounds
location until another Blink commit. This went unnoticed until now
because the root layer was not considered a scroller. The page would
paint into a document-sized layer and the compositor would provide extra
scrolling layers to handle frame scrolling. In this configuration, the
ToScreen transformation from the root layer does include the scroll
offset.

Now that root layer scrolling has been turned on, frame scrolling works
much the same as other scrollers. Thus, this shortcoming is seen on
frame scrolling also.

The solution in this CL is to move the selection bounds rect to be
relative to the scrolling contents layer - if one exists. The ToScreen
transformation done in CC will correctly compensate for any scroll
offset applied in the compositor and touch selection handles stick to
the selection as its scrolled. For the CC side, see
ComputeViewportSelectionBound in layer_tree_impl.cc

Reland Note: This patch makes the RenderedPositionTests run with mock
scrollbars.

TBR=chrishtr@chromium.org

Bug: 812048
Change-Id: Ib9eacd14b75b71b4e0d4f0a9b57416800f9dfb91
Reviewed-on: https://chromium-review.googlesource.com/967001Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Commit-Queue: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543803}
parent 870c2627
...@@ -248,8 +248,21 @@ Position RenderedPosition::PositionAtRightBoundaryOfBiDiRun() const { ...@@ -248,8 +248,21 @@ Position RenderedPosition::PositionAtRightBoundaryOfBiDiRun() const {
PrevLeafChild()->CaretRightmostOffset()); PrevLeafChild()->CaretRightmostOffset());
} }
// Note: If the layout object has a scrolling contents layer, the selection
// will be relative to that.
static GraphicsLayer* GetGraphicsLayerBacking(
const LayoutObject& layout_object) {
const LayoutBoxModelObject& paint_invalidation_container =
layout_object.ContainerForPaintInvalidation();
DCHECK(paint_invalidation_container.Layer());
if (paint_invalidation_container.Layer()->GetCompositingState() ==
kNotComposited)
return nullptr;
return paint_invalidation_container.Layer()->GraphicsLayerBacking(
&layout_object);
}
// Convert a local point into the coordinate system of backing coordinates. // Convert a local point into the coordinate system of backing coordinates.
// Also returns the backing layer if needed.
static FloatPoint LocalToInvalidationBackingPoint( static FloatPoint LocalToInvalidationBackingPoint(
const LayoutPoint& local_point, const LayoutPoint& local_point,
const LayoutObject& layout_object) { const LayoutObject& layout_object) {
...@@ -270,26 +283,18 @@ static FloatPoint LocalToInvalidationBackingPoint( ...@@ -270,26 +283,18 @@ static FloatPoint LocalToInvalidationBackingPoint(
PaintLayer::MapPointInPaintInvalidationContainerToBacking( PaintLayer::MapPointInPaintInvalidationContainerToBacking(
paint_invalidation_container, container_point); paint_invalidation_container, container_point);
// Must not use the scrolling contents layer, so pass if (GraphicsLayer* graphics_layer = GetGraphicsLayerBacking(layout_object))
// |paintInvalidationContainer|.
if (GraphicsLayer* graphics_layer =
paint_invalidation_container.Layer()->GraphicsLayerBacking(
&paint_invalidation_container))
container_point.Move(-graphics_layer->OffsetFromLayoutObject()); container_point.Move(-graphics_layer->OffsetFromLayoutObject());
return container_point; // Ensure the coordinates are in the scrolling contents space, if the object
} // is a scroller.
if (paint_invalidation_container.UsesCompositedScrolling()) {
container_point.Move(paint_invalidation_container.Layer()
->GetScrollableArea()
->GetScrollOffset());
}
static GraphicsLayer* GetGraphicsLayerBacking( return container_point;
const LayoutObject& layout_object) {
const LayoutBoxModelObject& paint_invalidation_container =
layout_object.ContainerForPaintInvalidation();
DCHECK(paint_invalidation_container.Layer());
if (paint_invalidation_container.Layer()->GetCompositingState() ==
kNotComposited)
return nullptr;
return paint_invalidation_container.Layer()->GraphicsLayerBacking(
&paint_invalidation_container);
} }
std::pair<LayoutPoint, LayoutPoint> static GetLocalSelectionStartpoints( std::pair<LayoutPoint, LayoutPoint> static GetLocalSelectionStartpoints(
......
...@@ -10,37 +10,59 @@ ...@@ -10,37 +10,59 @@
#include "core/editing/testing/EditingTestBase.h" #include "core/editing/testing/EditingTestBase.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "core/html/forms/HTMLInputElement.h" #include "core/html/forms/HTMLInputElement.h"
#include "core/layout/LayoutBox.h"
#include "core/paint/PaintLayerScrollableArea.h"
#include "core/paint/compositing/CompositedSelection.h" #include "core/paint/compositing/CompositedSelection.h"
#include "platform/testing/UseMockScrollbarSettings.h"
#include "platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink { namespace blink {
class RenderedPositionTest : public EditingTestBase {}; class RenderedPositionTest : public ::testing::WithParamInterface<bool>,
private ScopedRootLayerScrollingForTest,
#if defined(OS_ANDROID) public EditingTestBase {
#define MAYBE_ComputeCompositedSelection DISABLED_ComputeCompositedSelection public:
#else RenderedPositionTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
#define MAYBE_ComputeCompositedSelection ComputeCompositedSelection void SetUp() override {
#endif EditingTestBase::SetUp();
TEST_F(RenderedPositionTest, MAYBE_ComputeCompositedSelection) { GetPage().GetSettings().SetAcceleratedCompositingEnabled(true);
// Enable compositing. GetDocument().View()->SetParentVisible(true);
GetPage().GetSettings().SetAcceleratedCompositingEnabled(true); GetDocument().View()->SetSelfVisible(true);
GetDocument().View()->SetParentVisible(true); LoadAhem();
GetDocument().View()->SetSelfVisible(true); }
GetDocument().View()->UpdateAllLifecyclePhases();
void FocusAndSelectAll() {
SetBodyContent( HTMLInputElement* target =
"<input id=target width=20 value='test test test test test tes tes test'" ToHTMLInputElement(GetDocument().getElementById("target"));
"style='width: 100px; height: 20px;'>"); DCHECK(target);
HTMLInputElement* target = target->focus();
ToHTMLInputElement(GetDocument().getElementById("target")); Selection().SetSelection(
DCHECK(target); SelectionInDOMTree::Builder()
target->focus(); .SelectAllChildren(*target->InnerEditorElement())
Selection().SetSelection( .Build(),
SelectionInDOMTree::Builder() SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
.SelectAllChildren(*target->InnerEditorElement()) UpdateAllLifecyclePhases();
.Build(), }
SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
UpdateAllLifecyclePhases(); private:
UseMockScrollbarSettings mock_scrollbars_;
};
INSTANTIATE_TEST_CASE_P(All, RenderedPositionTest, ::testing::Bool());
TEST_P(RenderedPositionTest, ComputeCompositedSelection) {
SetBodyContent(R"HTML(
<!DOCTYPE html>
input {
font: 10px/1 Ahem;
padding: 0;
border: 0;
}
<input id=target width=20 value='test test test test test tes tes test'
style='width: 100px; height: 20px;'>
)HTML");
FocusAndSelectAll();
const CompositedSelection& composited_selection = const CompositedSelection& composited_selection =
RenderedPosition::ComputeCompositedSelection(Selection()); RenderedPosition::ComputeCompositedSelection(Selection());
...@@ -48,4 +70,115 @@ TEST_F(RenderedPositionTest, MAYBE_ComputeCompositedSelection) { ...@@ -48,4 +70,115 @@ TEST_F(RenderedPositionTest, MAYBE_ComputeCompositedSelection) {
EXPECT_TRUE(composited_selection.end.hidden); EXPECT_TRUE(composited_selection.end.hidden);
} }
TEST_P(RenderedPositionTest, PositionInScrollableRoot) {
SetBodyContent(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
height: 2000px;
width: 2000px;
}
input {
font: 10px/1 Ahem;
padding: 0;
border: 0;
width: 100px;
height: 20px;
position: absolute;
top: 900px;
left: 1000px;
}
</style>
<input id=target width=20 value='test test test test test tes tes test'>
)HTML");
FocusAndSelectAll();
ScrollableArea* root_scroller = GetDocument().View()->GetScrollableArea();
root_scroller->SetScrollOffset(ScrollOffset(800, 500), kProgrammaticScroll);
ASSERT_EQ(ScrollOffset(800, 500), root_scroller->GetScrollOffset());
UpdateAllLifecyclePhases();
const CompositedSelection& composited_selection =
RenderedPosition::ComputeCompositedSelection(Selection());
// Top-left corner should be around (1000, 905) - 10px centered in 20px
// height.
EXPECT_EQ(FloatPoint(1000, 905),
composited_selection.start.edge_top_in_layer);
EXPECT_EQ(FloatPoint(1000, 915),
composited_selection.start.edge_bottom_in_layer);
EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
EXPECT_EQ(FloatPoint(1369, 915),
composited_selection.end.edge_bottom_in_layer);
}
TEST_P(RenderedPositionTest, PositionInScroller) {
SetBodyContent(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
height: 2000px;
width: 2000px;
}
input {
font: 10px/1 Ahem;
padding: 0;
border: 0;
width: 100px;
height: 20px;
position: absolute;
top: 900px;
left: 1000px;
}
#scroller {
width: 300px;
height: 300px;
position: absolute;
left: 300px;
top: 400px;
overflow: scroll;
border: 200px;
will-change: transform;
}
#space {
width: 2000px;
height: 2000px;
}
</style>
<div id="scroller">
<div id="space"></div>
<input id=target width=20 value='test test test test test tes tes test'>
</div>
)HTML");
FocusAndSelectAll();
Element* e = GetDocument().getElementById("scroller");
PaintLayerScrollableArea* scroller =
ToLayoutBox(e->GetLayoutObject())->GetScrollableArea();
scroller->SetScrollOffset(ScrollOffset(900, 800), kProgrammaticScroll);
ASSERT_EQ(ScrollOffset(900, 800), scroller->GetScrollOffset());
UpdateAllLifecyclePhases();
const CompositedSelection& composited_selection =
RenderedPosition::ComputeCompositedSelection(Selection());
// Top-left corner should be around (1000, 905) - 10px centered in 20px
// height.
EXPECT_EQ(FloatPoint(1000, 905),
composited_selection.start.edge_top_in_layer);
EXPECT_EQ(FloatPoint(1000, 915),
composited_selection.start.edge_bottom_in_layer);
EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
EXPECT_EQ(FloatPoint(1369, 915),
composited_selection.end.edge_bottom_in_layer);
}
} // namespace blink } // namespace blink
...@@ -6332,11 +6332,7 @@ class CompositedSelectionBoundsTest ...@@ -6332,11 +6332,7 @@ class CompositedSelectionBoundsTest
blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck( blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck(
v8::Isolate::GetCurrent(), expected_result.Get(0)); v8::Isolate::GetCurrent(), expected_result.Get(0));
ASSERT_TRUE(layer_owner_node_for_start); ASSERT_TRUE(layer_owner_node_for_start);
EXPECT_EQ(layer_owner_node_for_start->GetLayoutObject() EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_start)
->EnclosingLayer()
->EnclosingLayerForPaintInvalidation()
->GetCompositedLayerMapping()
->MainGraphicsLayer()
->PlatformLayer() ->PlatformLayer()
->Id(), ->Id(),
select_start->layer_id); select_start->layer_id);
...@@ -6351,11 +6347,7 @@ class CompositedSelectionBoundsTest ...@@ -6351,11 +6347,7 @@ class CompositedSelectionBoundsTest
expected_result.Get(context, 5).ToLocalChecked()); expected_result.Get(context, 5).ToLocalChecked());
ASSERT_TRUE(layer_owner_node_for_end); ASSERT_TRUE(layer_owner_node_for_end);
EXPECT_EQ(layer_owner_node_for_end->GetLayoutObject() EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_end)
->EnclosingLayer()
->EnclosingLayerForPaintInvalidation()
->GetCompositedLayerMapping()
->MainGraphicsLayer()
->PlatformLayer() ->PlatformLayer()
->Id(), ->Id(),
select_end->layer_id); select_end->layer_id);
...@@ -6407,6 +6399,18 @@ class CompositedSelectionBoundsTest ...@@ -6407,6 +6399,18 @@ class CompositedSelectionBoundsTest
RunTest(test_file); RunTest(test_file);
} }
GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) const {
CompositedLayerMapping* clm = node->GetLayoutObject()
->EnclosingLayer()
->EnclosingLayerForPaintInvalidation()
->GetCompositedLayerMapping();
// If the Node is a scroller, the selection will be relative to its
// scrolling contents layer.
return clm->ScrollingContentsLayer() ? clm->ScrollingContentsLayer()
: clm->MainGraphicsLayer();
}
CompositedSelectionBoundsTestWebViewClient fake_selection_web_view_client_; CompositedSelectionBoundsTestWebViewClient fake_selection_web_view_client_;
CompositedSelectionBoundsTestLayerTreeView& fake_selection_layer_tree_view_; CompositedSelectionBoundsTestLayerTreeView& fake_selection_layer_tree_view_;
FrameTestHelpers::WebViewHelper web_view_helper_; FrameTestHelpers::WebViewHelper web_view_helper_;
......
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