Index: cc/trees/layer_tree_impl.cc |
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc |
index 0b9b880c2ba3b82c0663007549af7d58fec36ee3..26dd3d81911388682a76dd4794c1183a7ecd3223 100644 |
--- a/cc/trees/layer_tree_impl.cc |
+++ b/cc/trees/layer_tree_impl.cc |
@@ -1334,31 +1334,50 @@ void LayerTreeImpl::RegisterSelection(const LayerSelectionBound& start, |
} |
static ViewportSelectionBound ComputeViewportSelection( |
- const LayerSelectionBound& bound, |
+ const LayerSelectionBound& layer_bound, |
LayerImpl* layer, |
float device_scale_factor) { |
- ViewportSelectionBound result; |
- result.type = bound.type; |
+ ViewportSelectionBound viewport_bound; |
+ viewport_bound.type = layer_bound.type; |
- if (!layer || bound.type == SELECTION_BOUND_EMPTY) |
- return result; |
+ if (!layer || layer_bound.type == SELECTION_BOUND_EMPTY) |
+ return viewport_bound; |
- 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); |
+ gfx::PointF layer_scaled_top = gfx::ScalePoint(layer_bound.edge_top, |
+ layer->contents_scale_x(), |
+ layer->contents_scale_y()); |
+ gfx::PointF layer_scaled_bottom = gfx::ScalePoint(layer_bound.edge_bottom, |
+ layer->contents_scale_x(), |
+ layer->contents_scale_y()); |
- // 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 |
+ bool clipped = false; |
+ gfx::PointF screen_top = MathUtil::MapPoint( |
+ layer->screen_space_transform(), layer_scaled_top, &clipped); |
+ gfx::PointF screen_bottom = MathUtil::MapPoint( |
+ layer->screen_space_transform(), layer_scaled_bottom, &clipped); |
+ |
+ const float inv_scale = 1.f / device_scale_factor; |
+ viewport_bound.edge_top = gfx::ScalePoint(screen_top, inv_scale); |
+ viewport_bound.edge_bottom = gfx::ScalePoint(screen_bottom, inv_scale); |
+ |
+ // The bottom edge point is used for visibility testing as it 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); |
+ // Shifting the visibility point fractionally inward ensures that neighboring |
+ // or logically coincident layers aligned to integral DPI coordinates will not |
+ // spuriously occlude the bound. |
+ gfx::Vector2dF visibility_offset = layer_scaled_top - layer_scaled_bottom; |
+ visibility_offset.Scale(device_scale_factor / visibility_offset.Length()); |
+ gfx::PointF visibility_point = layer_scaled_bottom + visibility_offset; |
+ if (visibility_point.x() <= 0) |
+ visibility_point.set_x(visibility_point.x() + device_scale_factor); |
+ visibility_point = MathUtil::MapPoint( |
+ layer->screen_space_transform(), visibility_point, &clipped); |
- screen_rect.Scale(1.f / device_scale_factor); |
- result.viewport_rect = screen_rect; |
+ float intersect_distance = 0.f; |
+ viewport_bound.visible = |
+ PointHitsLayer(layer, visibility_point, &intersect_distance); |
- return result; |
+ return viewport_bound; |
} |
void LayerTreeImpl::GetViewportSelection(ViewportSelectionBound* start, |