summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-01 19:08:49 +0000
committerjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-01 19:08:49 +0000
commit19aec37d615420b1001e3f0505b06307a4fcfe0d (patch)
tree0790994e5d7c71e6496ed3c9ea4963dc2f0a87d6
parentadc6eb89e31942c80eda20db6abb1391c5b0a159 (diff)
downloadchromium_src-19aec37d615420b1001e3f0505b06307a4fcfe0d.zip
chromium_src-19aec37d615420b1001e3f0505b06307a4fcfe0d.tar.gz
chromium_src-19aec37d615420b1001e3f0505b06307a4fcfe0d.tar.bz2
Route selection bounds updates through the compositor
Currently, the selection bounds are queried at the start of each frame on the main thread. If the bounds differ from the previous bounds, an updated notification is sent to the browser. This approach is problematic for many reasons, the chief of which being the inability of such updates to remain in sync with content that is transformed on the compositor thread. Instead, plumb the selection bounds region through the compositor, anchoring each bound to the appropriate composited layer. This allows the compositor to generated transformed bounds synchronized with transformed content, passed to the browser with the CompositorFrameMetdadata. Note that this patch only implements the compositor portion of the plumbing. Enabling the feature in Blink and consuming the handle positions in the browser will be done in https://codereview.chromium.org/359033002. BUG=135959 Review URL: https://codereview.chromium.org/300323005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@280858 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--cc/cc.gyp5
-rw-r--r--cc/input/layer_selection_bound.cc27
-rw-r--r--cc/input/layer_selection_bound.h29
-rw-r--r--cc/input/selection_bound_type.h20
-rw-r--r--cc/output/compositor_frame_metadata.h6
-rw-r--r--cc/output/viewport_selection_bound.cc27
-rw-r--r--cc/output/viewport_selection_bound.h31
-rw-r--r--cc/trees/layer_tree_host.cc13
-rw-r--r--cc/trees/layer_tree_host.h7
-rw-r--r--cc/trees/layer_tree_host_impl.cc3
-rw-r--r--cc/trees/layer_tree_host_impl_unittest.cc53
-rw-r--r--cc/trees/layer_tree_impl.cc63
-rw-r--r--cc/trees/layer_tree_impl.h12
-rw-r--r--cc/trees/layer_tree_impl_unittest.cc249
-rw-r--r--content/common/cc_messages.h10
-rw-r--r--content/renderer/gpu/render_widget_compositor.cc36
-rw-r--r--content/renderer/gpu/render_widget_compositor.h4
-rw-r--r--content/test/web_layer_tree_view_impl_for_testing.cc8
-rw-r--r--content/test/web_layer_tree_view_impl_for_testing.h4
19 files changed, 604 insertions, 3 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 79b15c3..3f1444f 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -140,6 +140,9 @@
'input/input_handler.h',
'input/page_scale_animation.cc',
'input/page_scale_animation.h',
+ 'input/layer_selection_bound.cc',
+ 'input/layer_selection_bound.h',
+ 'input/selection_bound_type.h',
'input/top_controls_manager.cc',
'input/top_controls_manager.h',
'input/top_controls_manager_client.h',
@@ -295,6 +298,8 @@
'output/software_output_device.h',
'output/software_renderer.cc',
'output/software_renderer.h',
+ 'output/viewport_selection_bound.cc',
+ 'output/viewport_selection_bound.h',
'quads/checkerboard_draw_quad.cc',
'quads/checkerboard_draw_quad.h',
'quads/content_draw_quad_base.cc',
diff --git a/cc/input/layer_selection_bound.cc b/cc/input/layer_selection_bound.cc
new file mode 100644
index 0000000..c8054c4
--- /dev/null
+++ b/cc/input/layer_selection_bound.cc
@@ -0,0 +1,27 @@
+// Copyright 2014 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 "cc/input/layer_selection_bound.h"
+
+namespace cc {
+
+LayerSelectionBound::LayerSelectionBound()
+ : type(SELECTION_BOUND_EMPTY), layer_id(0) {
+}
+
+LayerSelectionBound::~LayerSelectionBound() {
+}
+
+bool operator==(const LayerSelectionBound& lhs,
+ const LayerSelectionBound& rhs) {
+ return lhs.type == rhs.type && lhs.layer_id == rhs.layer_id &&
+ lhs.layer_rect == rhs.layer_rect;
+}
+
+bool operator!=(const LayerSelectionBound& lhs,
+ const LayerSelectionBound& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace cc
diff --git a/cc/input/layer_selection_bound.h b/cc/input/layer_selection_bound.h
new file mode 100644
index 0000000..30b2c80
--- /dev/null
+++ b/cc/input/layer_selection_bound.h
@@ -0,0 +1,29 @@
+// Copyright 2014 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 CC_INPUT_LAYER_SELECTION_BOUND_H_
+#define CC_INPUT_LAYER_SELECTION_BOUND_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/selection_bound_type.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace cc {
+
+// Marker for a selection end-point attached to a specific layer.
+struct CC_EXPORT LayerSelectionBound {
+ LayerSelectionBound();
+ ~LayerSelectionBound();
+
+ SelectionBoundType type;
+ gfx::RectF layer_rect;
+ int layer_id;
+};
+
+bool operator==(const LayerSelectionBound& lhs, const LayerSelectionBound& rhs);
+bool operator!=(const LayerSelectionBound& lhs, const LayerSelectionBound& rhs);
+
+} // namespace cc
+
+#endif // CC_INPUT_LAYER_SELECTION_BOUND_H_
diff --git a/cc/input/selection_bound_type.h b/cc/input/selection_bound_type.h
new file mode 100644
index 0000000..5e1f9c4
--- /dev/null
+++ b/cc/input/selection_bound_type.h
@@ -0,0 +1,20 @@
+// Copyright 2014 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 CC_INPUT_SELECTION_BOUND_TYPE_H_
+#define CC_INPUT_SELECTION_BOUND_TYPE_H_
+
+namespace cc {
+
+enum SelectionBoundType {
+ SELECTION_BOUND_LEFT,
+ SELECTION_BOUND_RIGHT,
+ SELECTION_BOUND_CENTER,
+ SELECTION_BOUND_EMPTY,
+ SELECTION_BOUND_TYPE_LAST = SELECTION_BOUND_EMPTY
+};
+
+} // namespace cc
+
+#endif // CC_INPUT_SELECTION_BOUND_TYPE_H_
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index 54c3ce6..f21a2e3 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -8,6 +8,7 @@
#include <vector>
#include "cc/base/cc_export.h"
+#include "cc/output/viewport_selection_bound.h"
#include "ui/events/latency_info.h"
#include "ui/gfx/size_f.h"
#include "ui/gfx/vector2d_f.h"
@@ -40,6 +41,11 @@ class CC_EXPORT CompositorFrameMetadata {
gfx::Vector2dF location_bar_content_translation;
float overdraw_bottom_height;
+ // Provides selection region updates relative to the current viewport. If the
+ // selection is empty or otherwise unused, the bound types will indicate such.
+ ViewportSelectionBound selection_anchor;
+ ViewportSelectionBound selection_focus;
+
std::vector<ui::LatencyInfo> latency_info;
};
diff --git a/cc/output/viewport_selection_bound.cc b/cc/output/viewport_selection_bound.cc
new file mode 100644
index 0000000..cfcb829
--- /dev/null
+++ b/cc/output/viewport_selection_bound.cc
@@ -0,0 +1,27 @@
+// Copyright 2014 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 "cc/output/viewport_selection_bound.h"
+
+namespace cc {
+
+ViewportSelectionBound::ViewportSelectionBound()
+ : type(SELECTION_BOUND_EMPTY), visible(false) {
+}
+
+ViewportSelectionBound::~ViewportSelectionBound() {
+}
+
+bool operator==(const ViewportSelectionBound& lhs,
+ const ViewportSelectionBound& rhs) {
+ return lhs.type == rhs.type && lhs.visible == rhs.visible &&
+ lhs.viewport_rect == rhs.viewport_rect;
+}
+
+bool operator!=(const ViewportSelectionBound& lhs,
+ const ViewportSelectionBound& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace cc
diff --git a/cc/output/viewport_selection_bound.h b/cc/output/viewport_selection_bound.h
new file mode 100644
index 0000000..bb4ed12
--- /dev/null
+++ b/cc/output/viewport_selection_bound.h
@@ -0,0 +1,31 @@
+// Copyright 2014 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 CC_OUTPUT_VIEWPORT_SELECTION_BOUND_H_
+#define CC_OUTPUT_VIEWPORT_SELECTION_BOUND_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/selection_bound_type.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace cc {
+
+// Marker for a selection end-point in (DIP) viewport coordinates.
+struct CC_EXPORT ViewportSelectionBound {
+ ViewportSelectionBound();
+ ~ViewportSelectionBound();
+
+ SelectionBoundType type;
+ gfx::RectF viewport_rect;
+ bool visible;
+};
+
+CC_EXPORT bool operator==(const ViewportSelectionBound& lhs,
+ const ViewportSelectionBound& rhs);
+CC_EXPORT bool operator!=(const ViewportSelectionBound& lhs,
+ const ViewportSelectionBound& rhs);
+
+} // namespace cc
+
+#endif // CC_OUTPUT_VIEWPORT_SELECTION_BOUND_H_
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 51b9b4f..5f45c17 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -21,6 +21,7 @@
#include "cc/base/math_util.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/input/top_controls_manager.h"
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -315,6 +316,8 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->ClearViewportLayers();
}
+ sync_tree->RegisterSelection(selection_anchor_, selection_focus_);
+
float page_scale_delta =
sync_tree->page_scale_delta() / sync_tree->sent_page_scale_delta();
sync_tree->SetPageScaleValues(page_scale_factor_,
@@ -1221,6 +1224,16 @@ void LayerTreeHost::RegisterViewportLayers(
outer_viewport_scroll_layer_ = outer_viewport_scroll_layer;
}
+void LayerTreeHost::RegisterSelection(const LayerSelectionBound& anchor,
+ const LayerSelectionBound& focus) {
+ if (selection_anchor_ == anchor && selection_focus_ == focus)
+ return;
+
+ selection_anchor_ = anchor;
+ selection_focus_ = focus;
+ SetNeedsCommit();
+}
+
int LayerTreeHost::ScheduleMicroBenchmark(
const std::string& benchmark_name,
scoped_ptr<base::Value> value,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index ef6e74f..1d23c6c 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -27,6 +27,7 @@
#include "cc/debug/micro_benchmark.h"
#include "cc/debug/micro_benchmark_controller.h"
#include "cc/input/input_handler.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/input/scrollbar.h"
#include "cc/input/top_controls_state.h"
#include "cc/layers/layer_lists.h"
@@ -178,6 +179,9 @@ class CC_EXPORT LayerTreeHost {
return outer_viewport_scroll_layer_.get();
}
+ void RegisterSelection(const LayerSelectionBound& anchor,
+ const LayerSelectionBound& focus);
+
const LayerTreeSettings& settings() const { return settings_; }
void SetDebugState(const LayerTreeDebugState& debug_state);
@@ -439,6 +443,9 @@ class CC_EXPORT LayerTreeHost {
scoped_refptr<Layer> inner_viewport_scroll_layer_;
scoped_refptr<Layer> outer_viewport_scroll_layer_;
+ LayerSelectionBound selection_anchor_;
+ LayerSelectionBound selection_focus_;
+
SharedBitmapManager* shared_bitmap_manager_;
ScopedPtrVector<SwapPromise> swap_promise_list_;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 61eceea..c4f268dd 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1374,6 +1374,9 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const {
metadata.overdraw_bottom_height = overdraw_bottom_height_;
}
+ active_tree_->GetViewportSelection(&metadata.selection_anchor,
+ &metadata.selection_focus);
+
if (!InnerViewportScrollLayer())
return metadata;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 12bd88b..dc7b106 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -6291,6 +6291,59 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, NULL));
}
+TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
+ int root_layer_id = 1;
+ scoped_ptr<SolidColorLayerImpl> root =
+ SolidColorLayerImpl::Create(host_impl_->active_tree(), root_layer_id);
+ root->SetPosition(gfx::PointF());
+ root->SetBounds(gfx::Size(10, 10));
+ root->SetContentBounds(gfx::Size(10, 10));
+ root->SetDrawsContent(true);
+
+ host_impl_->active_tree()->SetRootLayer(root.PassAs<LayerImpl>());
+
+ // Ensure the default frame selection bounds are empty.
+ FakeOutputSurface* fake_output_surface =
+ static_cast<FakeOutputSurface*>(host_impl_->output_surface());
+ const ViewportSelectionBound& selection_anchor_before =
+ fake_output_surface->last_sent_frame().metadata.selection_anchor;
+ const ViewportSelectionBound& selection_focus_before =
+ fake_output_surface->last_sent_frame().metadata.selection_focus;
+ EXPECT_EQ(ViewportSelectionBound(), selection_anchor_before);
+ EXPECT_EQ(ViewportSelectionBound(), selection_focus_before);
+
+ // Plumb the layer-local selection bounds.
+ gfx::Rect selection_rect(5, 0, 0, 5);
+ LayerSelectionBound anchor, focus;
+ anchor.type = SELECTION_BOUND_CENTER;
+ anchor.layer_id = root_layer_id;
+ anchor.layer_rect = selection_rect;
+ focus = anchor;
+ host_impl_->active_tree()->RegisterSelection(anchor, focus);
+
+ // Trigger a draw-swap sequence.
+ host_impl_->SetNeedsRedraw();
+
+ gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_TRUE(host_impl_->SwapBuffers(frame));
+
+ // Ensure the selection bounds have propagated to the frame metadata.
+ const ViewportSelectionBound& selection_anchor_after =
+ fake_output_surface->last_sent_frame().metadata.selection_anchor;
+ const ViewportSelectionBound& selection_focus_after =
+ fake_output_surface->last_sent_frame().metadata.selection_focus;
+ EXPECT_EQ(anchor.type, selection_anchor_after.type);
+ EXPECT_EQ(focus.type, selection_focus_after.type);
+ EXPECT_EQ(selection_rect, selection_anchor_after.viewport_rect);
+ EXPECT_EQ(selection_rect, selection_anchor_after.viewport_rect);
+ EXPECT_TRUE(selection_anchor_after.visible);
+ EXPECT_TRUE(selection_anchor_after.visible);
+}
+
class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
public:
SimpleSwapPromiseMonitor(LayerTreeHost* layer_tree_host,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 2c0efdd..2dec1dc 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -210,6 +210,9 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
} else {
target_tree->ClearViewportLayers();
}
+
+ target_tree->RegisterSelection(selection_anchor_, selection_focus_);
+
// This should match the property synchronization in
// LayerTreeHost::finishCommitOnImplThread().
target_tree->set_source_frame_number(source_frame_number());
@@ -1122,7 +1125,7 @@ static bool PointHitsRegion(const gfx::PointF& screen_space_point,
gfx::ToRoundedPoint(hit_test_point_in_layer_space));
}
-static LayerImpl* GetNextClippingLayer(LayerImpl* layer) {
+static const LayerImpl* GetNextClippingLayer(const LayerImpl* layer) {
if (layer->scroll_parent())
return layer->scroll_parent();
if (layer->clip_parent())
@@ -1132,7 +1135,7 @@ static LayerImpl* GetNextClippingLayer(LayerImpl* layer) {
static bool PointIsClippedBySurfaceOrClipRect(
const gfx::PointF& screen_space_point,
- LayerImpl* layer) {
+ const LayerImpl* layer) {
// Walk up the layer tree and hit-test any render_surfaces and any layer
// clip rects that are active.
for (; layer; layer = GetNextClippingLayer(layer)) {
@@ -1156,7 +1159,7 @@ static bool PointIsClippedBySurfaceOrClipRect(
return false;
}
-static bool PointHitsLayer(LayerImpl* layer,
+static bool PointHitsLayer(const LayerImpl* layer,
const gfx::PointF& screen_space_point,
float* distance_to_intersection) {
gfx::RectF content_rect(layer->content_bounds());
@@ -1308,6 +1311,60 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
return data_for_recursion.closest_match;
}
+void LayerTreeImpl::RegisterSelection(const LayerSelectionBound& anchor,
+ const LayerSelectionBound& focus) {
+ selection_anchor_ = anchor;
+ selection_focus_ = focus;
+}
+
+static ViewportSelectionBound ComputeViewportSelection(
+ const LayerSelectionBound& bound,
+ LayerImpl* layer,
+ float device_scale_factor) {
+ ViewportSelectionBound result;
+ result.type = bound.type;
+
+ if (!layer || bound.type == SELECTION_BOUND_EMPTY)
+ return result;
+
+ gfx::RectF layer_scaled_rect = gfx::ScaleRect(
+ bound.layer_rect, layer->contents_scale_x(), layer->contents_scale_y());
+ gfx::RectF screen_rect = MathUtil::ProjectClippedRect(
+ layer->screen_space_transform(), layer_scaled_rect);
+
+ // The bottom left of the bound is used for visibility because 1) the bound
+ // edge rect is one-dimensional (no width), and 2) the bottom is the logical
+ // focal point for bound selection handles (this may change in the future).
+ const gfx::PointF& visibility_point = screen_rect.bottom_left();
+ float intersect_distance = 0.f;
+ result.visible = PointHitsLayer(layer, visibility_point, &intersect_distance);
+
+ screen_rect.Scale(1.f / device_scale_factor);
+ result.viewport_rect = screen_rect;
+
+ return result;
+}
+
+void LayerTreeImpl::GetViewportSelection(ViewportSelectionBound* anchor,
+ ViewportSelectionBound* focus) {
+ DCHECK(anchor);
+ DCHECK(focus);
+
+ *anchor = ComputeViewportSelection(
+ selection_anchor_,
+ selection_anchor_.layer_id ? LayerById(selection_anchor_.layer_id) : NULL,
+ device_scale_factor());
+ if (anchor->type == SELECTION_BOUND_CENTER ||
+ anchor->type == SELECTION_BOUND_EMPTY) {
+ *focus = *anchor;
+ } else {
+ *focus = ComputeViewportSelection(
+ selection_focus_,
+ selection_focus_.layer_id ? LayerById(selection_focus_.layer_id) : NULL,
+ device_scale_factor());
+ }
+}
+
void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
layer_tree_host_impl_->RegisterPictureLayerImpl(layer);
}
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 3b3c6cf..df39dcd2 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -48,6 +48,7 @@ class ResourceProvider;
class TileManager;
class UIResourceRequest;
struct RendererCapabilities;
+struct SelectionHandle;
typedef std::list<UIResourceRequest> UIResourceRequestQueue;
@@ -263,6 +264,14 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* FindLayerThatIsHitByPointInTouchHandlerRegion(
const gfx::PointF& screen_space_point);
+ void RegisterSelection(const LayerSelectionBound& anchor,
+ const LayerSelectionBound& focus);
+
+ // Compute the current selection handle location and visbility with respect to
+ // the viewport.
+ void GetViewportSelection(ViewportSelectionBound* anchor,
+ ViewportSelectionBound* focus);
+
void RegisterPictureLayerImpl(PictureLayerImpl* layer);
void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
@@ -287,6 +296,9 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* inner_viewport_scroll_layer_;
LayerImpl* outer_viewport_scroll_layer_;
+ LayerSelectionBound selection_anchor_;
+ LayerSelectionBound selection_focus_;
+
float page_scale_factor_;
float page_scale_delta_;
float sent_page_scale_delta_;
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index 006fc35..9edf838 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -2070,5 +2070,254 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
EXPECT_FALSE(result_layer);
}
+TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
+ int root_layer_id = 12345;
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), root_layer_id);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ LayerSelectionBound left_input;
+ left_input.type = SELECTION_BOUND_LEFT;
+ left_input.layer_rect = gfx::RectF(10, 10, 5, 20);
+ left_input.layer_id = root_layer_id;
+
+ LayerSelectionBound right_input;
+ right_input.type = SELECTION_BOUND_RIGHT;
+ right_input.layer_rect = gfx::RectF(50, 10, 5, 20);
+ right_input.layer_id = root_layer_id;
+
+ ViewportSelectionBound left_output, right_output;
+
+ // Empty input bounds should produce empty output bounds.
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_EQ(ViewportSelectionBound(), left_output);
+ EXPECT_EQ(ViewportSelectionBound(), right_output);
+
+ // Selection bounds should produce distinct left and right bounds.
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_EQ(left_input.type, left_output.type);
+ EXPECT_EQ(left_input.layer_rect, left_output.viewport_rect);
+ EXPECT_TRUE(left_output.visible);
+ EXPECT_EQ(right_input.type, right_output.type);
+ EXPECT_EQ(right_input.layer_rect, right_output.viewport_rect);
+ EXPECT_TRUE(right_output.visible);
+
+ // Insertion bounds should produce identical left and right bounds.
+ LayerSelectionBound insertion_input;
+ insertion_input.type = SELECTION_BOUND_CENTER;
+ insertion_input.layer_rect = gfx::RectF(10, 10, 5, 20);
+ insertion_input.layer_id = root_layer_id;
+ host_impl().active_tree()->RegisterSelection(insertion_input,
+ LayerSelectionBound());
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_EQ(insertion_input.type, left_output.type);
+ EXPECT_EQ(insertion_input.layer_rect, left_output.viewport_rect);
+ EXPECT_TRUE(left_output.visible);
+ EXPECT_EQ(left_output, right_output);
+}
+
+TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
+ int root_layer_id = 12345;
+ int clip_layer_id = 1234;
+ int clipped_layer_id = 123;
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), root_layer_id);
+ root->SetDrawsContent(true);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+
+ gfx::Vector2dF clipping_offset(10, 10);
+ {
+ scoped_ptr<LayerImpl> clipping_layer =
+ LayerImpl::Create(host_impl().active_tree(), clip_layer_id);
+ // The clipping layer should occlude the right selection bound.
+ gfx::PointF position = gfx::PointF() + clipping_offset;
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(clipping_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ clipping_layer->SetMasksToBounds(true);
+
+ scoped_ptr<LayerImpl> clipped_layer =
+ LayerImpl::Create(host_impl().active_tree(), clipped_layer_id);
+ position = gfx::PointF();
+ bounds = gfx::Size(100, 100);
+ SetLayerPropertiesForTesting(clipped_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ clipped_layer->SetDrawsContent(true);
+ clipping_layer->AddChild(clipped_layer.Pass());
+ root->AddChild(clipping_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+
+ LayerSelectionBound left_input;
+ left_input.type = SELECTION_BOUND_LEFT;
+ left_input.layer_rect = gfx::RectF(25, 10, 5, 20);
+ left_input.layer_id = clipped_layer_id;
+
+ LayerSelectionBound right_input;
+ right_input.type = SELECTION_BOUND_RIGHT;
+ right_input.layer_rect = gfx::RectF(75, 10, 5, 20);
+ right_input.layer_id = clipped_layer_id;
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+
+ // The left bound should be occluded by the clip layer.
+ ViewportSelectionBound left_output, right_output;
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_EQ(left_input.type, left_output.type);
+ gfx::RectF expected_left_output_rect = left_input.layer_rect;
+ expected_left_output_rect.Offset(clipping_offset);
+ EXPECT_EQ(expected_left_output_rect, left_output.viewport_rect);
+ EXPECT_TRUE(left_output.visible);
+ EXPECT_EQ(right_input.type, right_output.type);
+ gfx::RectF expected_right_output_rect = right_input.layer_rect;
+ expected_right_output_rect.Offset(clipping_offset);
+ EXPECT_EQ(expected_right_output_rect, right_output.viewport_rect);
+ EXPECT_FALSE(right_output.visible);
+
+ // Handles outside the viewport bounds should be marked invisible.
+ left_input.layer_rect = gfx::RectF(-25, 0, 5, 20);
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_FALSE(left_output.visible);
+
+ left_input.layer_rect = gfx::RectF(0, -25, 5, 20);
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_FALSE(left_output.visible);
+
+ // If the handle bottom is partially visible, the handle is marked visible.
+ left_input.layer_rect = gfx::RectF(0, -20, 5, 21);
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_TRUE(left_output.visible);
+}
+
+TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
+ int root_layer_id = 1;
+ int sub_layer_id = 2;
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), root_layer_id);
+ root->SetDrawsContent(true);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+
+ gfx::Vector2dF sub_layer_offset(10, 0);
+ {
+ scoped_ptr<LayerImpl> sub_layer =
+ LayerImpl::Create(host_impl().active_tree(), sub_layer_id);
+ gfx::PointF position = gfx::PointF() + sub_layer_offset;
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(sub_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ sub_layer->SetDrawsContent(true);
+ root->AddChild(sub_layer.Pass());
+ }
+
+ float device_scale_factor = 3.f;
+ float page_scale_factor = 5.f;
+ gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize(
+ gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor));
+ host_impl().SetViewportSize(scaled_bounds_for_root);
+
+ host_impl().SetDeviceScaleFactor(device_scale_factor);
+ host_impl().active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, page_scale_factor, page_scale_factor);
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID);
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+
+ LayerSelectionBound left_input;
+ left_input.type = SELECTION_BOUND_LEFT;
+ left_input.layer_rect = gfx::RectF(10, 10, 5, 20);
+ left_input.layer_id = root_layer_id;
+
+ LayerSelectionBound right_input;
+ right_input.type = SELECTION_BOUND_RIGHT;
+ right_input.layer_rect = gfx::RectF(0, 0, 5, 20);
+ right_input.layer_id = sub_layer_id;
+ host_impl().active_tree()->RegisterSelection(left_input, right_input);
+
+ // The viewport bounds should be properly scaled by the page scale, but should
+ // remain in DIP coordinates.
+ ViewportSelectionBound left_output, right_output;
+ host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
+ EXPECT_EQ(left_input.type, left_output.type);
+ gfx::RectF expected_left_output_rect = left_input.layer_rect;
+ expected_left_output_rect.Scale(page_scale_factor);
+ EXPECT_EQ(left_input.layer_rect, left_output.viewport_rect);
+ EXPECT_TRUE(left_output.visible);
+ EXPECT_EQ(right_input.type, right_output.type);
+ gfx::RectF expected_right_output_rect = right_input.layer_rect;
+ expected_right_output_rect.Offset(sub_layer_offset);
+ expected_right_output_rect.Scale(page_scale_factor);
+ EXPECT_EQ(expected_right_output_rect, right_output.viewport_rect);
+ EXPECT_TRUE(right_output.visible);
+}
+
} // namespace
} // namespace cc
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h
index 23714b4..59811aa 100644
--- a/content/common/cc_messages.h
+++ b/content/common/cc_messages.h
@@ -8,6 +8,7 @@
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/filter_operation.h"
+#include "cc/output/viewport_selection_bound.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/draw_quad.h"
@@ -132,6 +133,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(cc::IOSurfaceDrawQuad::Orientation,
IPC_ENUM_TRAITS_MAX_VALUE(cc::FilterOperation::FilterType,
cc::FilterOperation::FILTER_TYPE_LAST )
IPC_ENUM_TRAITS_MAX_VALUE(cc::ResourceFormat, cc::RESOURCE_FORMAT_MAX)
+IPC_ENUM_TRAITS_MAX_VALUE(cc::SelectionBoundType, cc::SELECTION_BOUND_TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(SkXfermode::Mode, SkXfermode::kLastMode)
IPC_ENUM_TRAITS_MAX_VALUE(cc::YUVVideoDrawQuad::ColorSpace,
cc::YUVVideoDrawQuad::COLOR_SPACE_LAST)
@@ -259,6 +261,12 @@ IPC_STRUCT_TRAITS_BEGIN(cc::ReturnedResource)
IPC_STRUCT_TRAITS_MEMBER(lost)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(cc::ViewportSelectionBound)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(viewport_rect)
+ IPC_STRUCT_TRAITS_MEMBER(visible)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(cc::BeginFrameArgs)
IPC_STRUCT_TRAITS_MEMBER(frame_time)
IPC_STRUCT_TRAITS_MEMBER(deadline)
@@ -276,6 +284,8 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
IPC_STRUCT_TRAITS_MEMBER(location_bar_offset)
IPC_STRUCT_TRAITS_MEMBER(location_bar_content_translation)
IPC_STRUCT_TRAITS_MEMBER(overdraw_bottom_height)
+ IPC_STRUCT_TRAITS_MEMBER(selection_anchor)
+ IPC_STRUCT_TRAITS_MEMBER(selection_focus)
IPC_STRUCT_TRAITS_MEMBER(latency_info)
IPC_STRUCT_TRAITS_END()
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 33612b0..67e26fa 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -19,6 +19,7 @@
#include "cc/base/switches.h"
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/debug/micro_benchmark.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/layers/layer.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
@@ -33,6 +34,7 @@
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h"
+#include "third_party/WebKit/public/platform/WebSelectionBound.h"
#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/WebKit/public/web/WebWidget.h"
#include "ui/gfx/frame_time.h"
@@ -48,6 +50,7 @@ class Layer;
}
using blink::WebFloatPoint;
+using blink::WebSelectionBound;
using blink::WebSize;
using blink::WebRect;
@@ -73,6 +76,27 @@ bool GetSwitchValueAsInt(
}
}
+cc::LayerSelectionBound ConvertWebSelectionBound(
+ const WebSelectionBound& bound) {
+ DCHECK(bound.layerId);
+
+ cc::LayerSelectionBound result;
+ switch (bound.type) {
+ case blink::WebSelectionBound::Caret:
+ result.type = cc::SELECTION_BOUND_CENTER;
+ break;
+ case blink::WebSelectionBound::SelectionLeft:
+ result.type = cc::SELECTION_BOUND_LEFT;
+ break;
+ case blink::WebSelectionBound::SelectionRight:
+ result.type = cc::SELECTION_BOUND_RIGHT;
+ break;
+ }
+ result.layer_id = bound.layerId;
+ result.layer_rect = gfx::Rect(bound.edgeRectInLayer);
+ return result;
+}
+
} // namespace
// static
@@ -567,6 +591,18 @@ void RenderWidgetCompositor::clearViewportLayers() {
scoped_refptr<cc::Layer>());
}
+void RenderWidgetCompositor::registerSelection(
+ const blink::WebSelectionBound& anchor,
+ const blink::WebSelectionBound& focus) {
+ layer_tree_host_->RegisterSelection(ConvertWebSelectionBound(anchor),
+ ConvertWebSelectionBound(focus));
+}
+
+void RenderWidgetCompositor::clearSelection() {
+ cc::LayerSelectionBound empty_selection;
+ layer_tree_host_->RegisterSelection(empty_selection, empty_selection);
+}
+
void CompositeAndReadbackAsyncCallback(
blink::WebCompositeAndReadbackAsyncCallback* callback,
scoped_ptr<cc::CopyOutputResult> result) {
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 4160df2..fe33b7c 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -115,6 +115,10 @@ class RenderWidgetCompositor : public blink::WebLayerTreeView,
const blink::WebLayer* innerViewportScrollLayer,
const blink::WebLayer* outerViewportScrollLayer) OVERRIDE;
virtual void clearViewportLayers() OVERRIDE;
+ virtual void registerSelection(
+ const blink::WebSelectionBound& anchor,
+ const blink::WebSelectionBound& focus) OVERRIDE;
+ virtual void clearSelection() OVERRIDE;
virtual void setShowFPSCounter(bool show);
virtual void setShowPaintRects(bool show);
virtual void setShowDebugBorders(bool show);
diff --git a/content/test/web_layer_tree_view_impl_for_testing.cc b/content/test/web_layer_tree_view_impl_for_testing.cc
index 23c55f6..3c63295 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.cc
+++ b/content/test/web_layer_tree_view_impl_for_testing.cc
@@ -167,4 +167,12 @@ void WebLayerTreeViewImplForTesting::clearViewportLayers() {
scoped_refptr<cc::Layer>());
}
+void WebLayerTreeViewImplForTesting::registerSelection(
+ const blink::WebSelectionBound& anchor,
+ const blink::WebSelectionBound& focus) {
+}
+
+void WebLayerTreeViewImplForTesting::clearSelection() {
+}
+
} // namespace content
diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h
index c2b60c5..a30a74e 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.h
+++ b/content/test/web_layer_tree_view_impl_for_testing.h
@@ -59,6 +59,10 @@ class WebLayerTreeViewImplForTesting
const blink::WebLayer* innerViewportScrollLayer,
const blink::WebLayer* outerViewportScrollLayer) OVERRIDE;
virtual void clearViewportLayers() OVERRIDE;
+ virtual void registerSelection(
+ const blink::WebSelectionBound& anchor,
+ const blink::WebSelectionBound& focus) OVERRIDE;
+ virtual void clearSelection() OVERRIDE;
// cc::LayerTreeHostClient implementation.
virtual void WillBeginMainFrame(int frame_id) OVERRIDE {}