Commit fe956c9c authored by trchen@chromium.org's avatar trchen@chromium.org

Implement pinch zoom for bottom-right fixed-position elements

This patch adds a fixed container size compensation matrix to fixed-position
layers, so fixed-position layers can be anchored to right / bottom edge during
a pinch gesture.

WebKit side: https://bugs.webkit.org/show_bug.cgi?id=111670

BUG=160223


Review URL: https://chromiumcodereview.appspot.com/12552004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192999 0039d316-1c4b-4281-b951-d872f2087c98
parent bc76cc51
......@@ -110,6 +110,8 @@
'layers/layer_iterator.h',
'layers/layer_lists.h',
'resources/layer_painter.h',
'layers/layer_position_constraint.cc',
'layers/layer_position_constraint.h',
'resources/layer_quad.cc',
'resources/layer_quad.h',
'trees/layer_sorter.cc',
......
......@@ -25,6 +25,7 @@
'animation/layer_animation_controller_unittest.cc',
'layers/layer_impl_unittest.cc',
'layers/layer_iterator_unittest.cc',
'layers/layer_position_constraint_unittest.cc',
'resources/layer_quad_unittest.cc',
'trees/layer_sorter_unittest.cc',
'trees/layer_tree_host_common_unittest.cc',
......
......@@ -42,7 +42,6 @@ Layer::Layer()
opacity_(1.f),
anchor_point_z_(0.f),
is_container_for_fixed_position_layers_(false),
fixed_to_container_layer_(false),
is_drawable_(false),
masks_to_bounds_(false),
contents_opaque_(false),
......@@ -416,6 +415,14 @@ void Layer::SetPosition(gfx::PointF position) {
SetNeedsCommit();
}
bool Layer::IsContainerForFixedPositionLayers() const {
if (!transform_.IsIdentityOrTranslation())
return true;
if (parent_ && !parent_->sublayer_transform_.IsIdentityOrTranslation())
return true;
return is_container_for_fixed_position_layers_;
}
void Layer::SetSublayerTransform(const gfx::Transform& sublayer_transform) {
if (sublayer_transform_ == sublayer_transform)
return;
......@@ -533,7 +540,7 @@ void Layer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
bool Layer::DescendantIsFixedToContainerLayer() const {
for (size_t i = 0; i < children_.size(); ++i) {
if (children_[i]->fixed_to_container_layer() ||
if (children_[i]->position_constraint_.is_fixed_position() ||
children_[i]->DescendantIsFixedToContainerLayer())
return true;
}
......@@ -553,11 +560,11 @@ void Layer::SetIsContainerForFixedPositionLayers(bool container) {
SetNeedsCommit();
}
void Layer::SetFixedToContainerLayer(bool fixed_to_container_layer) {
if (fixed_to_container_layer_ == fixed_to_container_layer)
return;
fixed_to_container_layer_ = fixed_to_container_layer;
SetNeedsCommit();
void Layer::SetPositionConstraint(const LayerPositionConstraint& constraint) {
if (position_constraint_ == constraint)
return;
position_constraint_ = constraint;
SetNeedsCommit();
}
void Layer::PushPropertiesTo(LayerImpl* layer) {
......@@ -587,8 +594,9 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
DCHECK(!(OpacityIsAnimating() && layer->OpacityIsAnimatingOnImplOnly()));
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
is_container_for_fixed_position_layers_);
layer->SetFixedToContainerLayer(fixed_to_container_layer_);
IsContainerForFixedPositionLayers());
layer->SetFixedContainerSizeDelta(gfx::Vector2dF());
layer->SetPositionConstraint(position_constraint_);
layer->SetPreserves3d(preserves_3d());
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
layer->SetSublayerTransform(sublayer_transform_);
......
......@@ -16,6 +16,7 @@
#include "cc/base/region.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/render_surface.h"
#include "cc/trees/occlusion_tracker.h"
#include "skia/ext/refptr.h"
......@@ -124,12 +125,12 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
gfx::PointF position() const { return position_; }
void SetIsContainerForFixedPositionLayers(bool container);
bool is_container_for_fixed_position_layers() const {
return is_container_for_fixed_position_layers_;
}
bool IsContainerForFixedPositionLayers() const;
void SetFixedToContainerLayer(bool fixed_to_container_layer);
bool fixed_to_container_layer() const { return fixed_to_container_layer_; }
void SetPositionConstraint(const LayerPositionConstraint& constraint);
const LayerPositionConstraint& position_constraint() const {
return position_constraint_;
}
void SetSublayerTransform(const gfx::Transform& sublayer_transform);
const gfx::Transform& sublayer_transform() const {
......@@ -449,7 +450,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
WebKit::WebFilterOperations background_filters_;
float anchor_point_z_;
bool is_container_for_fixed_position_layers_;
bool fixed_to_container_layer_;
LayerPositionConstraint position_constraint_;
bool is_drawable_;
bool masks_to_bounds_;
bool contents_opaque_;
......
......@@ -50,7 +50,6 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
draws_content_(false),
force_render_surface_(false),
is_container_for_fixed_position_layers_(false),
fixed_to_container_layer_(false),
draw_depth_(0.f),
#ifndef NDEBUG
between_will_draw_and_did_draw_(false),
......@@ -341,7 +340,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
is_container_for_fixed_position_layers_);
layer->SetFixedToContainerLayer(fixed_to_container_layer_);
layer->SetFixedContainerSizeDelta(fixed_container_size_delta_);
layer->SetPositionConstraint(position_constraint_);
layer->SetPreserves3d(preserves_3d());
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
layer->SetSublayerTransform(sublayer_transform_);
......
......@@ -18,6 +18,7 @@
#include "cc/input/input_handler.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/shared_quad_state.h"
......@@ -157,14 +158,24 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
void SetIsContainerForFixedPositionLayers(bool container) {
is_container_for_fixed_position_layers_ = container;
}
bool is_container_for_fixed_position_layers() const {
// This is a non-trivial function in Layer.
bool IsContainerForFixedPositionLayers() const {
return is_container_for_fixed_position_layers_;
}
void SetFixedToContainerLayer(bool fixed) {
fixed_to_container_layer_ = fixed;
void SetFixedContainerSizeDelta(const gfx::Vector2dF& delta) {
fixed_container_size_delta_ = delta;
}
const gfx::Vector2dF& fixed_container_size_delta() const {
return fixed_container_size_delta_;
}
void SetPositionConstraint(const LayerPositionConstraint& constraint) {
position_constraint_ = constraint;
}
const LayerPositionConstraint& position_constraint() const {
return position_constraint_;
}
bool fixed_to_container_layer() const { return fixed_to_container_layer_; }
void SetPreserves3d(bool preserves_3d);
bool preserves_3d() const { return preserves_3d_; }
......@@ -475,9 +486,11 @@ class CC_EXPORT LayerImpl : LayerAnimationValueObserver {
// Set for the layer that other layers are fixed to.
bool is_container_for_fixed_position_layers_;
// This is true if the layer should be fixed to the closest ancestor
// container.
bool fixed_to_container_layer_;
// This property is effective when
// is_container_for_fixed_position_layers_ == true,
gfx::Vector2dF fixed_container_size_delta_;
LayerPositionConstraint position_constraint_;
gfx::Vector2dF scroll_delta_;
gfx::Vector2d sent_scroll_delta_;
......
// Copyright 2013 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/layers/layer_position_constraint.h"
namespace cc {
LayerPositionConstraint::LayerPositionConstraint()
: is_fixed_position_(false),
is_fixed_to_right_edge_(false),
is_fixed_to_bottom_edge_(false) {
}
bool LayerPositionConstraint::operator==(
const LayerPositionConstraint& other) const {
if (!is_fixed_position_ && !other.is_fixed_position_)
return true;
return is_fixed_position_ == other.is_fixed_position_ &&
is_fixed_to_right_edge_ == other.is_fixed_to_right_edge_ &&
is_fixed_to_bottom_edge_ == other.is_fixed_to_bottom_edge_;
}
bool LayerPositionConstraint::operator!=(
const LayerPositionConstraint& other) const {
return !(*this == other);
}
} // namespace cc
// Copyright 2013 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_LAYER_POSITION_CONSTRAINT_H_
#define CC_LAYER_POSITION_CONSTRAINT_H_
#include "cc/base/cc_export.h"
namespace cc {
class CC_EXPORT LayerPositionConstraint {
public:
LayerPositionConstraint();
void set_is_fixed_position(bool fixed) { is_fixed_position_ = fixed; }
bool is_fixed_position() const { return is_fixed_position_; }
void set_is_fixed_to_right_edge(bool fixed) {
is_fixed_to_right_edge_ = fixed;
}
bool is_fixed_to_right_edge() const { return is_fixed_to_right_edge_; }
void set_is_fixed_to_bottom_edge(bool fixed) {
is_fixed_to_bottom_edge_ = fixed;
}
bool is_fixed_to_bottom_edge() const { return is_fixed_to_bottom_edge_; }
bool operator==(const LayerPositionConstraint&) const;
bool operator!=(const LayerPositionConstraint&) const;
private:
bool is_fixed_position_ : 1;
bool is_fixed_to_right_edge_ : 1;
bool is_fixed_to_bottom_edge_ : 1;
};
} // namespace cc
#endif // CC_LAYER_POSITION_CONSTRAINT_H_
This diff is collapsed.
......@@ -342,6 +342,120 @@ static bool SubtreeShouldRenderToSeparateSurface(
return false;
}
static LayerImpl* NextTargetSurface(LayerImpl* layer) {
return layer->parent() ? layer->parent()->render_target() : 0;
}
// This function returns a translation matrix that can be applied on a vector
// that's in the layer's target surface coordinate, while the position offset is
// specified in some ancestor layer's coordinate.
gfx::Transform ComputeSizeDeltaCompensation(
LayerImpl* layer,
LayerImpl* container,
const gfx::Vector2dF& position_offset) {
gfx::Transform result_transform;
// To apply a translate in the container's layer space,
// the following steps need to be done:
// Step 1a. transform from target surface space to the container's target
// surface space
// Step 1b. transform from container's target surface space to the
// container's layer space
// Step 2. apply the compensation
// Step 3. transform back to target surface space
gfx::Transform target_surface_space_to_container_layer_space;
// Calculate step 1a
LayerImpl* container_target_surface =
container ? container->render_target() : 0;
for (LayerImpl* current_target_surface = NextTargetSurface(layer);
current_target_surface &&
current_target_surface != container_target_surface;
current_target_surface = NextTargetSurface(current_target_surface)) {
// Note: Concat is used here to convert the result coordinate space from
// current render surface to the next render surface.
target_surface_space_to_container_layer_space.ConcatTransform(
current_target_surface->render_surface()->draw_transform());
}
// Calculate step 1b
if (container) {
gfx::Transform container_layer_space_to_container_target_surface_space =
container->draw_transform();
container_layer_space_to_container_target_surface_space.Scale(
container->contents_scale_x(), container->contents_scale_y());
gfx::Transform container_target_surface_space_to_container_layer_space;
if (container_layer_space_to_container_target_surface_space.GetInverse(
&container_target_surface_space_to_container_layer_space)) {
// Note: Again, Concat is used to conver the result coordinate space from
// the container render surface to the container layer.
target_surface_space_to_container_layer_space.ConcatTransform(
container_target_surface_space_to_container_layer_space);
}
}
// Apply step 3
gfx::Transform container_layer_space_to_target_surface_space;
if (target_surface_space_to_container_layer_space.GetInverse(
&container_layer_space_to_target_surface_space))
result_transform.PreconcatTransform(
container_layer_space_to_target_surface_space);
else {
// FIXME: A non-invertible matrix could still make meaningful projection.
// For example ScaleZ(0) is non-invertible but the layer is still visible.
return gfx::Transform();
}
// Apply step 2
result_transform.Translate(position_offset.x(), position_offset.y());
// Apply step 1
result_transform.PreconcatTransform(
target_surface_space_to_container_layer_space);
return result_transform;
}
void ApplyPositionAdjustment(
Layer* layer,
Layer* container,
const gfx::Transform& scroll_compensation,
gfx::Transform* combined_transform) { }
void ApplyPositionAdjustment(
LayerImpl* layer,
LayerImpl* container,
const gfx::Transform& scroll_compensation,
gfx::Transform* combined_transform)
{
if (!layer->position_constraint().is_fixed_position())
return;
// Special case: this layer is a composited fixed-position layer; we need to
// explicitly compensate for all ancestors' nonzero scroll_deltas to keep
// this layer fixed correctly.
// Note carefully: this is Concat, not Preconcat
// (current_scroll_compensation * combined_transform).
combined_transform->ConcatTransform(scroll_compensation);
// For right-edge or bottom-edge anchored fixed position layers,
// the layer should relocate itself if the container changes its size.
bool fixed_to_right_edge =
layer->position_constraint().is_fixed_to_right_edge();
bool fixed_to_bottom_edge =
layer->position_constraint().is_fixed_to_bottom_edge();
gfx::Vector2dF position_offset =
container ? container->fixed_container_size_delta() : gfx::Vector2dF();
position_offset.set_x(fixed_to_right_edge ? position_offset.x() : 0);
position_offset.set_y(fixed_to_bottom_edge ? position_offset.y() : 0);
if (position_offset.IsZero())
return;
// Note: Again, this is Concat. The compensation matrix will be applied on
// the vector in target surface space.
combined_transform->ConcatTransform(
ComputeSizeDeltaCompensation(layer, container, position_offset));
}
gfx::Transform ComputeScrollCompensationForThisLayer(
LayerImpl* scrolling_layer,
const gfx::Transform& parent_matrix) {
......@@ -425,7 +539,7 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren(
// Avoid the overheads (including stack allocation and matrix
// initialization/copy) if we know that the scroll compensation doesn't need
// to be reset or adjusted.
if (!layer->is_container_for_fixed_position_layers() &&
if (!layer->IsContainerForFixedPositionLayers() &&
layer->scroll_delta().IsZero() && !layer->render_surface())
return current_scroll_compensation_matrix;
......@@ -434,7 +548,7 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren(
// If this layer is not a container, then it inherits the existing scroll
// compensations.
if (!layer->is_container_for_fixed_position_layers())
if (!layer->IsContainerForFixedPositionLayers())
next_scroll_compensation_matrix = current_scroll_compensation_matrix;
// If the current layer has a non-zero scroll_delta, then we should compute
......@@ -636,6 +750,7 @@ static void CalculateDrawPropertiesInternal(
const gfx::Transform& parent_matrix,
const gfx::Transform& full_hierarchy_matrix,
const gfx::Transform& current_scroll_compensation_matrix,
LayerType* current_fixed_container,
gfx::Rect clip_rect_from_ancestor,
gfx::Rect clip_rect_from_ancestor_in_descendant_space,
bool ancestor_clips_subtree,
......@@ -859,14 +974,9 @@ static void CalculateDrawPropertiesInternal(
RoundTranslationComponents(&combined_transform);
}
if (layer->fixed_to_container_layer()) {
// Special case: this layer is a composited fixed-position layer; we need to
// explicitly compensate for all ancestors' nonzero scroll_deltas to keep
// this layer fixed correctly.
// Note carefully: this is Concat, not Preconcat
// (current_scroll_compensation * combined_transform).
combined_transform.ConcatTransform(current_scroll_compensation_matrix);
}
// Apply adjustment from position constraints.
ApplyPositionAdjustment(layer, current_fixed_container,
current_scroll_compensation_matrix, &combined_transform);
// The draw_transform that gets computed below is effectively the layer's
// draw_transform, unless the layer itself creates a render_surface. In that
......@@ -1105,6 +1215,9 @@ static void CalculateDrawPropertiesInternal(
gfx::Transform next_scroll_compensation_matrix =
ComputeScrollCompensationMatrixForChildren(
layer, parent_matrix, current_scroll_compensation_matrix);
LayerType* next_fixed_container =
layer->IsContainerForFixedPositionLayers() ?
layer : current_fixed_container;
gfx::Rect accumulated_drawable_content_rect_of_children;
for (size_t i = 0; i < layer->children().size(); ++i) {
......@@ -1116,6 +1229,7 @@ static void CalculateDrawPropertiesInternal(
sublayer_matrix,
next_hierarchy_matrix,
next_scroll_compensation_matrix,
next_fixed_container,
clip_rect_for_subtree,
clip_rect_for_subtree_in_descendant_space,
subtree_should_be_clipped,
......@@ -1323,6 +1437,7 @@ void LayerTreeHostCommon::CalculateDrawProperties(
device_scale_transform,
identity_matrix,
identity_matrix,
NULL,
device_viewport_rect,
device_viewport_rect,
subtree_should_be_clipped,
......@@ -1376,6 +1491,7 @@ void LayerTreeHostCommon::CalculateDrawProperties(
device_scale_transform,
identity_matrix,
identity_matrix,
NULL,
device_viewport_rect,
device_viewport_rect,
subtree_should_be_clipped,
......
This diff is collapsed.
......@@ -259,6 +259,9 @@ struct UpdateTilePrioritiesForLayer {
};
void LayerTreeImpl::UpdateDrawProperties(UpdateDrawPropertiesReason reason) {
if (IsActiveTree() && RootScrollLayer() && RootClipLayer())
UpdateRootScrollLayerSizeDelta();
if (settings().solid_color_scrollbars &&
IsActiveTree() &&
RootScrollLayer()) {
......@@ -666,4 +669,23 @@ bool LayerTreeImpl::HasPinchZoomScrollbars() const {
pinch_zoom_scrollbar_vertical_layer_id_ != Layer::INVALID_ID;
}
void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() {
LayerImpl* root_scroll = RootScrollLayer();
LayerImpl* root_clip = RootClipLayer();
DCHECK(root_scroll);
DCHECK(root_clip);
DCHECK(IsActiveTree());
gfx::Vector2dF scrollable_viewport_size =
gfx::RectF(ScrollableViewportSize()).bottom_right() - gfx::PointF();
gfx::Vector2dF original_viewport_size =
gfx::RectF(root_clip->bounds()).bottom_right() -
gfx::PointF();
original_viewport_size.Scale(1 / page_scale_factor());
root_scroll->SetFixedContainerSizeDelta(
scrollable_viewport_size - original_viewport_size);
}
} // namespace cc
......@@ -211,6 +211,8 @@ class CC_EXPORT LayerTreeImpl {
ScrollbarLayerImpl* PinchZoomScrollbarVertical();
bool HasPinchZoomScrollbars() const;
void UpdateRootScrollLayerSizeDelta();
LayerTreeHostImpl* layer_tree_host_impl_;
int source_frame_number_;
scoped_ptr<LayerImpl> root_layer_;
......
......@@ -8,8 +8,10 @@
#include "cc/animation/animation.h"
#include "cc/base/region.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_position_constraint.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebFloatPoint.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebFloatRect.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebLayerPositionConstraint.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include "third_party/skia/include/utils/SkMatrix44.h"
#include "webkit/compositor_bindings/web_animation_impl.h"
......@@ -308,15 +310,34 @@ void WebLayerImpl::setIsContainerForFixedPositionLayers(bool enable) {
}
bool WebLayerImpl::isContainerForFixedPositionLayers() const {
return layer_->is_container_for_fixed_position_layers();
return layer_->IsContainerForFixedPositionLayers();
}
void WebLayerImpl::setFixedToContainerLayer(bool enable) {
layer_->SetFixedToContainerLayer(enable);
static WebKit::WebLayerPositionConstraint ToWebLayerPositionConstraint(
const cc::LayerPositionConstraint& constraint) {
WebKit::WebLayerPositionConstraint web_constraint;
web_constraint.isFixedPosition = constraint.is_fixed_position();
web_constraint.isFixedToRightEdge = constraint.is_fixed_to_right_edge();
web_constraint.isFixedToBottomEdge = constraint.is_fixed_to_bottom_edge();
return web_constraint;
}
bool WebLayerImpl::fixedToContainerLayer() const {
return layer_->fixed_to_container_layer();
static cc::LayerPositionConstraint ToLayerPositionConstraint(
const WebKit::WebLayerPositionConstraint& web_constraint) {
cc::LayerPositionConstraint constraint;
constraint.set_is_fixed_position(web_constraint.isFixedPosition);
constraint.set_is_fixed_to_right_edge(web_constraint.isFixedToRightEdge);
constraint.set_is_fixed_to_bottom_edge(web_constraint.isFixedToBottomEdge);
return constraint;
}
void WebLayerImpl::setPositionConstraint(
const WebKit::WebLayerPositionConstraint& constraint) {
layer_->SetPositionConstraint(ToLayerPositionConstraint(constraint));
}
WebKit::WebLayerPositionConstraint WebLayerImpl::positionConstraint() const {
return ToWebLayerPositionConstraint(layer_->position_constraint());
}
void WebLayerImpl::setScrollClient(
......
......@@ -110,8 +110,9 @@ class WebLayerImpl : public WebKit::WebLayer {
virtual WebKit::WebVector<WebKit::WebRect> touchEventHandlerRegion() const;
virtual void setIsContainerForFixedPositionLayers(bool is_container);
virtual bool isContainerForFixedPositionLayers() const;
virtual void setFixedToContainerLayer(bool is_fixed);
virtual bool fixedToContainerLayer() const;
virtual void setPositionConstraint(
const WebKit::WebLayerPositionConstraint& constraint);
virtual WebKit::WebLayerPositionConstraint positionConstraint() const;
virtual void setScrollClient(WebKit::WebLayerScrollClient* client);
virtual bool isOrphan() const;
......
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