summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_about_handler.cc21
-rw-r--r--chrome/browser/ui/touch/animation/screen_rotation.cc234
-rw-r--r--chrome/browser/ui/touch/animation/screen_rotation.h143
-rw-r--r--chrome/browser/ui/touch/animation/screen_rotation_setter.cc125
-rw-r--r--chrome/browser/ui/touch/animation/screen_rotation_setter.h22
-rw-r--r--chrome/browser/ui/touch/frame/touch_browser_frame_view.cc67
-rw-r--r--chrome/browser/ui/touch/frame/touch_browser_frame_view.h12
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/common/url_constants.cc1
-rw-r--r--chrome/common/url_constants.h1
-rw-r--r--ui/gfx/compositor/compositor.cc24
-rw-r--r--ui/gfx/compositor/compositor.gyp6
-rw-r--r--ui/gfx/compositor/compositor.h20
-rw-r--r--ui/gfx/compositor/compositor_gl.cc4
-rw-r--r--ui/gfx/compositor/compositor_gl.h4
-rw-r--r--ui/gfx/compositor/compositor_observer.h23
-rw-r--r--ui/gfx/compositor/compositor_stub.cc16
-rw-r--r--ui/gfx/compositor/compositor_win.cc8
-rw-r--r--ui/gfx/interpolated_transform.cc154
-rw-r--r--ui/gfx/interpolated_transform.h45
-rw-r--r--ui/gfx/interpolated_transform_unittest.cc42
-rw-r--r--views/paint_lock.cc19
-rw-r--r--views/paint_lock.h35
-rw-r--r--views/view.cc9
-rw-r--r--views/view.h9
-rw-r--r--views/views.gyp2
26 files changed, 1014 insertions, 36 deletions
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 12661de..e460e21 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -48,6 +48,7 @@
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/sensors/sensors_provider.h"
#include "content/common/gpu/gpu_messages.h"
#include "crypto/nss_util.h"
#include "googleurl/src/gurl.h"
@@ -1491,6 +1492,26 @@ bool WillHandleBrowserAboutURL(GURL* url,
} else if (host == chrome::kChromeUIGpuHangHost) {
GpuProcessHost::SendOnIO(
0, content::CAUSE_FOR_GPU_LAUNCH_ABOUT_GPUHANG, new GpuMsg_Hang());
+#if defined(OS_CHROMEOS)
+ } else if (host == chrome::kChromeUIRotateHost) {
+ sensors::ScreenOrientation change;
+ std::string query(url->query());
+ if (query == "left") {
+ change.upward = sensors::ScreenOrientation::LEFT;
+ } else if (query == "right") {
+ change.upward = sensors::ScreenOrientation::RIGHT;
+ } else if (query == "top") {
+ change.upward = sensors::ScreenOrientation::TOP;
+ } else if (query == "bottom") {
+ change.upward = sensors::ScreenOrientation::BOTTOM;
+ } else {
+ NOTREACHED() << "Unknown orientation";
+ }
+ sensors::Provider::GetInstance()->ScreenOrientationChanged(change);
+ // Nothing to communicate to the user, so show a blank page.
+ host = chrome::kChromeUIBlankHost;
+ *url = GURL(chrome::kChromeUIBlankHost);
+#endif
}
// Initialize any potentially corresponding AboutSource handler.
diff --git a/chrome/browser/ui/touch/animation/screen_rotation.cc b/chrome/browser/ui/touch/animation/screen_rotation.cc
new file mode 100644
index 0000000..7f3a053
--- /dev/null
+++ b/chrome/browser/ui/touch/animation/screen_rotation.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2011 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 "chrome/browser/ui/touch/animation/screen_rotation.h"
+
+#include "base/debug/trace_event.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "ui/base/animation/slide_animation.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/interpolated_transform.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/transform.h"
+#include "views/paint_lock.h"
+#include "views/view.h"
+#include "views/widget/widget.h"
+
+namespace {
+const int kDefaultTransitionDurationMs = 350;
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenRotationListener public:
+//
+
+ScreenRotationListener::~ScreenRotationListener() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenRotation public:
+//
+
+ScreenRotation::ScreenRotation(views::View* view,
+ ScreenRotationListener* listener,
+ float old_degrees,
+ float new_degrees)
+ : view_(view),
+ widget_(view->GetWidget()),
+ listener_(listener),
+ old_degrees_(old_degrees),
+ new_degrees_(new_degrees),
+ last_t_(0.0),
+ duration_(kDefaultTransitionDurationMs),
+ animation_started_(false),
+ animation_stopped_(false) {
+ DCHECK(view);
+ DCHECK(listener);
+
+ if (!view->layer() || !widget_) {
+ Finalize();
+ } else {
+ // Screen rotations are trigged as a result of a call to SetTransform which
+ // causes a paint to be scheduled to occur. At this point, the paint has
+ // been scheduled, but has not yet been started. We will listen for this
+ // paint to be completed before we start animating.
+ view->layer()->compositor()->AddObserver(this);
+ }
+}
+
+ScreenRotation::~ScreenRotation() {
+ if (view_->layer())
+ view_->layer()->compositor()->RemoveObserver(this);
+}
+
+void ScreenRotation::SetTarget(float degrees) {
+ if (new_degrees_ == degrees)
+ return;
+
+ new_degrees_ = degrees;
+ Init();
+}
+
+void ScreenRotation::Stop() {
+ animation_.reset();
+ if (view_->layer()) {
+ if (!interpolated_transform_.get()) {
+ // attempt to initialize.
+ Init();
+ }
+ if (interpolated_transform_.get()) {
+ view_->layer()->SetTransform(interpolated_transform_->Interpolate(1.0));
+ view_->GetWidget()->SchedulePaintInRect(
+ view_->GetWidget()->GetClientAreaScreenBounds());
+ }
+ }
+ Finalize();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScreenRotation private:
+//
+
+void ScreenRotation::AnimationProgressed(const ui::Animation* anim) {
+ TRACE_EVENT0("ScreenRotation", "step");
+ last_t_ = static_cast<float>(anim->GetCurrentValue());
+ view_->layer()->SetTransform(interpolated_transform_->Interpolate(last_t_));
+ widget_->SchedulePaintInRect(widget_->GetClientAreaScreenBounds());
+}
+
+void ScreenRotation::AnimationEnded(const ui::Animation* anim) {
+ TRACE_EVENT_END0("ScreenRotation", "ScreenRotation");
+ // TODO(vollick) massage matrix so that entries sufficiently close
+ // to 0, 1, or -1 are clamped to these values. The idea is to fight
+ // accumulated numeric error due to successive rotations.
+ ui::Transform xform = view_->layer()->transform();
+ gfx::Point origin;
+ xform.TransformPoint(origin);
+ ui::Transform translation;
+ translation.SetTranslate(new_origin_.x() - origin.x(),
+ new_origin_.y() - origin.y());
+ xform.ConcatTransform(translation);
+ view_->layer()->SetTransform(xform);
+ widget_->SchedulePaintInRect(widget_->GetClientAreaScreenBounds());
+ animation_stopped_ = true;
+}
+
+void ScreenRotation::OnCompositingEnded() {
+ DoPendingWork();
+}
+
+void ScreenRotation::Init() {
+ TRACE_EVENT0("ScreenRotation", "init");
+
+ ui::Transform current_transform = view_->layer()->transform();
+ int degrees = new_degrees_ - old_degrees_;
+ degrees = NormalizeAngle(degrees);
+
+ // No rotation required.
+ if (degrees == 0)
+ return;
+
+ gfx::Point old_pivot;
+ gfx::Point new_pivot;
+ int width = view_->layer()->bounds().width();
+ int height = view_->layer()->bounds().height();
+
+ switch (degrees) {
+ case 90:
+ new_origin_ = new_pivot = gfx::Point(width, 0);
+ new_size_.SetSize(height, width);
+ break;
+ case -90:
+ new_origin_ = new_pivot = gfx::Point(0, height);
+ new_size_.SetSize(height, width);
+ break;
+ case 180:
+ duration_ = 550;
+ new_pivot = old_pivot = gfx::Point(width / 2, height / 2);
+ new_origin_.SetPoint(width, height);
+ new_size_.SetSize(width, height);
+ break;
+ }
+
+ // Convert points to world space.
+ current_transform.TransformPoint(old_pivot);
+ current_transform.TransformPoint(new_pivot);
+ current_transform.TransformPoint(new_origin_);
+
+ scoped_ptr<ui::InterpolatedTransform> rotation(
+ new ui::InterpolatedTransformAboutPivot(
+ old_pivot,
+ new ui::InterpolatedRotation(0, degrees)));
+
+ scoped_ptr<ui::InterpolatedTransform> translation(
+ new ui::InterpolatedTranslation(
+ gfx::Point(0, 0),
+ gfx::Point(new_pivot.x() - old_pivot.x(),
+ new_pivot.y() - old_pivot.y())));
+
+ float scale_factor = 0.9f;
+ scoped_ptr<ui::InterpolatedTransform> scale_down(
+ new ui::InterpolatedScale(1.0f, scale_factor, 0.0f, 0.5f));
+
+ scoped_ptr<ui::InterpolatedTransform> scale_up(
+ new ui::InterpolatedScale(1.0f, 1.0f / scale_factor, 0.5f, 1.0f));
+
+ scoped_ptr<ui::InterpolatedTransform> transition(
+ new ui::InterpolatedConstantTransform(current_transform));
+
+ scale_up->SetChild(scale_down.release());
+ translation->SetChild(scale_up.release());
+ rotation->SetChild(translation.release());
+ transition->SetChild(rotation.release());
+
+ if (interpolated_transform_.get()) {
+ // We are in the middle of a transition. In this case, we need to create
+ // an interpolated transform that gets us from where we are to the target
+ // transform.
+ ui::Transform target = transition->Interpolate(1.0);
+ interpolated_transform_.reset(
+ new ui::InterpolatedTRSTransform(
+ current_transform, target, last_t_, 1.0));
+ } else {
+ interpolated_transform_.reset(transition.release());
+ }
+}
+
+void ScreenRotation::Start() {
+ TRACE_EVENT_BEGIN0("ScreenRotation", "ScreenRotation");
+ Init();
+ if (interpolated_transform_.get()) {
+ paint_lock_.reset(new views::PaintLock(view_));
+ animation_.reset(new ui::SlideAnimation(this));
+ animation_->SetTweenType(ui::Tween::LINEAR);
+ animation_->SetSlideDuration(duration_);
+ animation_->Show();
+ animation_started_ = true;
+ } else {
+ Finalize();
+ }
+}
+
+void ScreenRotation::Finalize() {
+ ui::Transform final_transform = view_->GetTransform();
+ gfx::Rect final_bounds(0, 0, new_size_.width(), new_size_.height());
+ listener_->OnScreenRotationCompleted(final_transform, final_bounds);
+}
+
+int ScreenRotation::NormalizeAngle(int degrees) {
+ while (degrees <= -180) degrees += 360;
+ while (degrees > 180) degrees -= 360;
+ return degrees;
+}
+
+void ScreenRotation::DoPendingWork() {
+ if (!animation_started_)
+ Start();
+ else if (animation_stopped_) {
+ view_->layer()->compositor()->RemoveObserver(this);
+ Finalize();
+ }
+}
diff --git a/chrome/browser/ui/touch/animation/screen_rotation.h b/chrome/browser/ui/touch/animation/screen_rotation.h
new file mode 100644
index 0000000..42f2fba
--- /dev/null
+++ b/chrome/browser/ui/touch/animation/screen_rotation.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2011 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 CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_H_
+#define CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/bind.h"
+#include "ui/base/animation/animation_delegate.h"
+#include "ui/gfx/compositor/compositor_observer.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/size.h"
+
+namespace ui {
+class InterpolatedTransform;
+class Layer;
+class SlideAnimation;
+class Transform;
+}
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+class PaintLock;
+class View;
+class Widget;
+}
+
+// Classes that wish to be notified when a screen rotation completes must
+// implement the screen rotation listener interface.
+class ScreenRotationListener {
+ public:
+ virtual void OnScreenRotationCompleted(const ui::Transform& target_transform,
+ const gfx::Rect& target_bounds) = 0;
+ protected:
+ virtual ~ScreenRotationListener();
+};
+
+// A screen rotation represents a single transition from one screen orientation
+// to another. The intended usage is that a new instance of the class is
+// created for every transition. It is possible to update the target orientation
+// in the middle of a transition.
+class ScreenRotation : public ui::AnimationDelegate,
+ public ui::CompositorObserver {
+ public:
+ // The screen rotation does not own the view or the listener, and these
+ // objects are required to outlive the Screen rotation object.
+ ScreenRotation(views::View* view,
+ ScreenRotationListener* listener,
+ float old_degrees,
+ float new_degrees);
+ virtual ~ScreenRotation();
+
+ // Use this function to change the target orientation mid animation. The
+ // currently running transition will complete at the same time as it was going
+ // to originally, but in a different orientation.
+ void SetTarget(float degrees);
+
+ // Aborts the animation by skipping to the end and applying the final
+ // transform before calling |Finalize|.
+ void Stop();
+
+ private:
+ // Implementation of ui::AnimationDelegate
+ virtual void AnimationEnded(const ui::Animation* anim) OVERRIDE;
+ virtual void AnimationProgressed(const ui::Animation* anim) OVERRIDE;
+
+ // Implementation of ui::CompositorObserver
+ void OnCompositingEnded() OVERRIDE;
+
+ // Initializes |interpolated_transform_|, |new_origin_|, |new_size_|, and
+ // (if it has not already been initialized) |old_transform_|
+ void Init();
+
+ // Initializes the screen rotation and starts |animation_|.
+ void Start();
+
+ // Called after the animation is finished and the view has completed painting
+ // in its final state.
+ void Finalize();
+
+ // Converts degrees to an angle in the range [-180, 180).
+ int NormalizeAngle(int degrees);
+
+ // We occasionally need to wait for a paint to finish before progressing.
+ // This function (which is triggered by OnPainted and OnComposited) does
+ // any pending work.
+ void DoPendingWork();
+
+ // This is the view that will be animated. The animation will operate mainly
+ // on |view_|'s layer, but it is used upon completion of the rotation to
+ // update the bounds.
+ views::View* view_;
+
+ // This widget will be used for scheduling paints.
+ views::Widget* widget_;
+
+ // A ScreenRotation may be associated with a listener that is notified when
+ // the screen rotation completes.
+ ScreenRotationListener* listener_;
+
+ // The animation object that instigates stepping of the animation.
+ scoped_ptr<ui::SlideAnimation> animation_;
+
+ // Generates the intermediate transformation matrices used during the
+ // animation.
+ scoped_ptr<ui::InterpolatedTransform> interpolated_transform_;
+
+ // Ensures that the view is not repainted during the screen rotation.
+ scoped_ptr<views::PaintLock> paint_lock_;
+
+ // The original orientation (not updated by |SetTarget|.
+ float old_degrees_;
+
+ // The target orientation.
+ float new_degrees_;
+
+ // We keep track of the last step of the animation in case we change our
+ // target in the middle and have to create a new transition from last_t_ to 1
+ float last_t_;
+
+ // The target size for |view_|
+ gfx::Size new_size_;
+
+ // The target origin for |view_|
+ gfx::Point new_origin_;
+
+ // This is the duration of the transition in milliseconds
+ int duration_;
+
+ // These are used by DoPendingWork to decide what needs to be done.
+ bool animation_started_;
+ bool animation_stopped_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenRotation);
+};
+
+#endif // CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_H_
diff --git a/chrome/browser/ui/touch/animation/screen_rotation_setter.cc b/chrome/browser/ui/touch/animation/screen_rotation_setter.cc
new file mode 100644
index 0000000..1b83fae
--- /dev/null
+++ b/chrome/browser/ui/touch/animation/screen_rotation_setter.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2011 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 "chrome/browser/ui/touch/animation/screen_rotation_setter.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/ui/touch/animation/screen_rotation.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/interpolated_transform.h"
+#include "views/layer_property_setter.h"
+#include "views/view.h"
+
+namespace {
+
+static int SymmetricRound(float x) {
+ return static_cast<int>(
+ x > 0
+ ? std::floor(x + 0.5f)
+ : std::ceil(x - 0.5f));
+}
+
+// A screen rotation setter is a LayerPropertySetter that initiates screen
+// rotations in response to calls to |SetTransform|. Calls to |SetBounds| are
+// applied to the layer immediately.
+class ScreenRotationSetter : public views::LayerPropertySetter,
+ public ScreenRotationListener {
+ public:
+ explicit ScreenRotationSetter(views::View* view);
+
+ // implementation of LayerPropertySetter
+ virtual void Installed(ui::Layer* layer) OVERRIDE;
+ virtual void Uninstalled(ui::Layer* layer) OVERRIDE;
+ virtual void SetTransform(ui::Layer* layer,
+ const ui::Transform& transform) OVERRIDE;
+ virtual void SetBounds(ui::Layer* layer, const gfx::Rect& bounds) OVERRIDE;
+
+ // implementation of ScreenRotationListener
+ virtual void OnScreenRotationCompleted(const ui::Transform& final_transform,
+ const gfx::Rect& final_rect) OVERRIDE;
+
+ private:
+ // This is the currently animating rotation. We hang onto it so that if a
+ // call to |SetTransform| is made during the rotation, we can update the
+ // target orientation of this rotation.
+ scoped_ptr<ScreenRotation> rotation_;
+
+ // If a call to set bounds happens during a rotation its effect is delayed
+ // until the rotation completes. If this happens several times, only the last
+ // call to SetBounds will have any effect.
+ scoped_ptr<gfx::Rect> pending_bounds_;
+
+ // The screen rotation setter is associated with a view so that the view's
+ // bounds may be set when the animation completes.
+ views::View* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenRotationSetter);
+};
+
+
+ScreenRotationSetter::ScreenRotationSetter(views::View* view) : view_(view) {
+}
+
+void ScreenRotationSetter::Installed(ui::Layer* layer) OVERRIDE {
+}
+
+void ScreenRotationSetter::Uninstalled(ui::Layer* layer) OVERRIDE {
+ if (rotation_.get())
+ rotation_->Stop();
+}
+
+void ScreenRotationSetter::SetTransform(ui::Layer* layer,
+ const ui::Transform& transform) {
+ float degrees;
+ if (!ui::InterpolatedTransform::FactorTRS(transform, NULL, &degrees, NULL))
+ return;
+
+ if (rotation_.get()) {
+ rotation_->SetTarget(SymmetricRound(degrees));
+ } else {
+ float old_degrees;
+ if (ui::InterpolatedTransform::FactorTRS(layer->transform(),
+ NULL,
+ &old_degrees,
+ NULL)) {
+ rotation_.reset(new ScreenRotation(view_,
+ this,
+ SymmetricRound(old_degrees),
+ SymmetricRound(degrees)));
+ }
+ }
+}
+
+void ScreenRotationSetter::SetBounds(ui::Layer* layer,
+ const gfx::Rect& bounds) {
+ // cache bounds changes during an animation.
+ if (rotation_.get())
+ pending_bounds_.reset(new gfx::Rect(bounds));
+ else
+ layer->SetBounds(bounds);
+}
+
+void ScreenRotationSetter::OnScreenRotationCompleted(
+ const ui::Transform& final_transform,
+ const gfx::Rect& final_bounds) {
+ // destroy the animation.
+ rotation_.reset();
+ if (pending_bounds_.get() && view_->layer()) {
+ // If there are any pending bounds changes, they will have already been
+ // applied to the view, and are waiting to be applied to the layer.
+ view_->layer()->SetBounds(*pending_bounds_);
+ pending_bounds_.reset();
+ } else {
+ // Otherwise we may have new bounds as the result of the completed screen
+ // rotation. Apply these to the view.
+ view_->SetBoundsRect(final_bounds);
+ }
+}
+
+} // namespace
+
+views::LayerPropertySetter* ScreenRotationSetterFactory::Create(
+ views::View* view) {
+ return new ScreenRotationSetter(view);
+}
diff --git a/chrome/browser/ui/touch/animation/screen_rotation_setter.h b/chrome/browser/ui/touch/animation/screen_rotation_setter.h
new file mode 100644
index 0000000..aad8a03
--- /dev/null
+++ b/chrome/browser/ui/touch/animation/screen_rotation_setter.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 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 CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_SETTER_H_
+#define CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_SETTER_H_
+#pragma once
+
+#include "views/layer_property_setter.h"
+
+namespace views {
+class View;
+}
+
+class ScreenRotationSetterFactory {
+ public:
+ // The setter will not own the view, and it is required that the view
+ // outlive the setter.
+ static views::LayerPropertySetter* Create(views::View* view);
+};
+
+#endif // CHROME_BROWSER_UI_TOUCH_ANIMATION_SCREEN_ROTATION_SETTER_H_
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
index 47708be1..f5fd86c 100644
--- a/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.cc
@@ -4,8 +4,46 @@
#include "chrome/browser/ui/touch/frame/touch_browser_frame_view.h"
+#include "chrome/browser/ui/touch/animation/screen_rotation_setter.h"
#include "chrome/browser/ui/touch/keyboard/keyboard_manager.h"
#include "views/controls/button/image_button.h"
+#include "views/desktop/desktop_window_view.h"
+#include "ui/gfx/transform.h"
+
+namespace {
+
+ui::Transform SideToTransform(sensors::ScreenOrientation::Side side,
+ const ui::Transform& old_transform,
+ const gfx::Size& size) {
+ gfx::Point origin;
+ gfx::Point bottom_right(size.width(), size.height());
+ old_transform.TransformPoint(origin);
+ old_transform.TransformPoint(bottom_right);
+ int original_width = abs(origin.x() - bottom_right.x());
+ int original_height = abs(origin.y() - bottom_right.y());
+ ui::Transform to_return;
+ switch (side) {
+ case sensors::ScreenOrientation::TOP: break;
+ case sensors::ScreenOrientation::RIGHT:
+ to_return.ConcatRotate(90);
+ to_return.ConcatTranslate(original_width, 0);
+ break;
+ case sensors::ScreenOrientation::LEFT:
+ to_return.ConcatRotate(-90);
+ to_return.ConcatTranslate(0, original_height);
+ break;
+ case sensors::ScreenOrientation::BOTTOM:
+ to_return.ConcatRotate(180);
+ to_return.ConcatTranslate(original_width, original_height);
+ break;
+ default:
+ to_return = old_transform;
+ break;
+ }
+ return to_return;
+}
+
+} // namespace
// static
const char TouchBrowserFrameView::kViewClassName[] =
@@ -19,9 +57,11 @@ TouchBrowserFrameView::TouchBrowserFrameView(BrowserFrame* frame,
: OpaqueBrowserFrameView(frame, browser_view) {
// Make sure the singleton KeyboardManager object is initialized.
KeyboardManager::GetInstance();
+ sensors::Provider::GetInstance()->AddListener(this);
}
TouchBrowserFrameView::~TouchBrowserFrameView() {
+ sensors::Provider::GetInstance()->RemoveListener(this);
}
std::string TouchBrowserFrameView::GetClassName() const {
@@ -47,3 +87,30 @@ bool TouchBrowserFrameView::HitTest(const gfx::Point& point) const {
return false;
}
+
+void TouchBrowserFrameView::OnScreenOrientationChanged(
+ const sensors::ScreenOrientation& change) {
+ // In views desktop mode, then the desktop_window_view will not be NULL and
+ // is the view to be rotated.
+ views::View* to_rotate =
+ views::desktop::DesktopWindowView::desktop_window_view;
+
+ if (!to_rotate) {
+ // Otherwise, rotate the widget's view.
+ views::Widget* widget = GetWidget();
+ to_rotate = widget->GetRootView();
+ }
+
+ if (!initialized_screen_rotation_) {
+ to_rotate->SetPaintToLayer(true);
+ to_rotate->SetLayerPropertySetter(
+ ScreenRotationSetterFactory::Create(to_rotate));
+ initialized_screen_rotation_ = true;
+ }
+
+ ui::Transform xform = SideToTransform(change.upward,
+ to_rotate->GetTransform(),
+ to_rotate->size());
+ to_rotate->SetTransform(xform);
+}
+
diff --git a/chrome/browser/ui/touch/frame/touch_browser_frame_view.h b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
index 4329b07..5e4eefb 100644
--- a/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
+++ b/chrome/browser/ui/touch/frame/touch_browser_frame_view.h
@@ -8,11 +8,15 @@
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
+#include "content/browser/sensors/sensors_provider.h"
+#include "content/common/sensors.h"
+
class BrowserFrame;
class BrowserView;
class TouchBrowserFrameView
- : public OpaqueBrowserFrameView {
+ : public OpaqueBrowserFrameView,
+ public sensors::Listener {
public:
// Internal class name.
static const char kViewClassName[];
@@ -21,11 +25,17 @@ class TouchBrowserFrameView
TouchBrowserFrameView(BrowserFrame* frame, BrowserView* browser_view);
virtual ~TouchBrowserFrameView();
+ // sensors::Listener implementation
+ virtual void OnScreenOrientationChanged(
+ const sensors::ScreenOrientation& change) OVERRIDE;
+
private:
// Overridden from views::View
virtual std::string GetClassName() const OVERRIDE;
virtual bool HitTest(const gfx::Point& point) const OVERRIDE;
+ bool initialized_screen_rotation_;
+
DISALLOW_COPY_AND_ASSIGN(TouchBrowserFrameView);
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 29f494f..38d929d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3085,6 +3085,10 @@
'browser/ui/toolbar/wrench_menu_model.cc',
'browser/ui/toolbar/wrench_menu_model.h',
'browser/ui/toolbar/wrench_menu_model_chromeos.cc',
+ 'browser/ui/touch/animation/screen_rotation.cc',
+ 'browser/ui/touch/animation/screen_rotation.h',
+ 'browser/ui/touch/animation/screen_rotation_setter.cc',
+ 'browser/ui/touch/animation/screen_rotation_setter.h',
'browser/ui/touch/frame/browser_non_client_frame_view_factory_touch.cc',
'browser/ui/touch/frame/touch_browser_frame_view.cc',
'browser/ui/touch/frame/touch_browser_frame_view.h',
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 115bc41..78e3298 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -189,6 +189,7 @@ const char kChromeUIOobeHost[] = "oobe";
const char kChromeUIOSCreditsHost[] = "os-credits";
const char kChromeUIProxySettingsHost[] = "proxy-settings";
const char kChromeUIRegisterPageHost[] = "register";
+const char kChromeUIRotateHost[] = "rotate";
const char kChromeUISlideshowHost[] = "slideshow";
const char kChromeUISimUnlockHost[] = "sim-unlock";
const char kChromeUISystemInfoHost[] = "system";
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 7da0eec..e6f8313 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -187,6 +187,7 @@ extern const char kChromeUIOobeHost[];
extern const char kChromeUIOSCreditsHost[];
extern const char kChromeUIProxySettingsHost[];
extern const char kChromeUIRegisterPageHost[];
+extern const char kChromeUIRotateHost[];
extern const char kChromeUISlideshowHost[];
extern const char kChromeUISimUnlockHost[];
extern const char kChromeUISystemInfoHost[];
diff --git a/ui/gfx/compositor/compositor.cc b/ui/gfx/compositor/compositor.cc
index ed7a4dd..24f7a08 100644
--- a/ui/gfx/compositor/compositor.cc
+++ b/ui/gfx/compositor/compositor.cc
@@ -3,14 +3,28 @@
// found in the LICENSE file.
#include "ui/gfx/compositor/compositor.h"
+#include "ui/gfx/compositor/compositor_observer.h"
namespace ui {
-// static
-Compositor* Compositor::Create(CompositorDelegate* delegate,
- gfx::AcceleratedWidget widget,
- const gfx::Size& size) {
- return NULL;
+void Compositor::NotifyStart() {
+ OnNotifyStart();
}
+void Compositor::NotifyEnd() {
+ OnNotifyEnd();
+ FOR_EACH_OBSERVER(CompositorObserver,
+ observer_list_,
+ OnCompositingEnded());
+}
+
+void Compositor::AddObserver(CompositorObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void Compositor::RemoveObserver(CompositorObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+
} // namespace ui
diff --git a/ui/gfx/compositor/compositor.gyp b/ui/gfx/compositor/compositor.gyp
index a429703..117bf06 100644
--- a/ui/gfx/compositor/compositor.gyp
+++ b/ui/gfx/compositor/compositor.gyp
@@ -39,6 +39,8 @@
'compositor_export.h',
'compositor_gl.cc',
'compositor_gl.h',
+ 'compositor_observer.h',
+ 'compositor_stub.cc',
'compositor_win.cc',
'layer.cc',
'layer.h',
@@ -48,12 +50,12 @@
'conditions': [
['os_posix == 1 and OS != "mac"', {
'sources!': [
- 'compositor.cc',
+ 'compositor_stub.cc',
],
}],
['OS == "win" and views_compositor == 1', {
'sources!': [
- 'compositor.cc',
+ 'compositor_stub.cc',
],
# TODO(sky): before we make this real need to remove
# IDR_BITMAP_BRUSH_IMAGE.
diff --git a/ui/gfx/compositor/compositor.h b/ui/gfx/compositor/compositor.h
index 59c71e5..ce28051 100644
--- a/ui/gfx/compositor/compositor.h
+++ b/ui/gfx/compositor/compositor.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
#include "ui/gfx/compositor/compositor_export.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/native_widget_types.h"
@@ -20,6 +21,8 @@ class Rect;
namespace ui {
+class CompositorObserver;
+
struct TextureDrawParams {
TextureDrawParams() : transform(), blend(false), compositor_size() {}
@@ -86,10 +89,10 @@ class COMPOSITOR_EXPORT Compositor : public base::RefCounted<Compositor> {
virtual Texture* CreateTexture() = 0;
// Notifies the compositor that compositing is about to start.
- virtual void NotifyStart() = 0;
+ void NotifyStart();
// Notifies the compositor that compositing is complete.
- virtual void NotifyEnd() = 0;
+ void NotifyEnd();
// Blurs the specific region in the compositor.
virtual void Blur(const gfx::Rect& bounds) = 0;
@@ -109,12 +112,23 @@ class COMPOSITOR_EXPORT Compositor : public base::RefCounted<Compositor> {
// Returns the size of the widget that is being drawn to.
const gfx::Size& size() { return size_; }
+ // Layers do not own observers. It is the responsibility of the observer to
+ // remove itself when it is done observing.
+ void AddObserver(CompositorObserver* observer);
+ void RemoveObserver(CompositorObserver* observer);
+
protected:
Compositor(CompositorDelegate* delegate, const gfx::Size& size)
: delegate_(delegate),
size_(size) {}
virtual ~Compositor() {}
+ // Notifies the compositor that compositing is about to start.
+ virtual void OnNotifyStart() = 0;
+
+ // Notifies the compositor that compositing is complete.
+ virtual void OnNotifyEnd() = 0;
+
virtual void OnWidgetSizeChanged() = 0;
CompositorDelegate* delegate() { return delegate_; }
@@ -123,6 +137,8 @@ class COMPOSITOR_EXPORT Compositor : public base::RefCounted<Compositor> {
CompositorDelegate* delegate_;
gfx::Size size_;
+ ObserverList<CompositorObserver> observer_list_;
+
friend class base::RefCounted<Compositor>;
};
diff --git a/ui/gfx/compositor/compositor_gl.cc b/ui/gfx/compositor/compositor_gl.cc
index 1c4833f..c3775c2 100644
--- a/ui/gfx/compositor/compositor_gl.cc
+++ b/ui/gfx/compositor/compositor_gl.cc
@@ -470,7 +470,7 @@ Texture* CompositorGL::CreateTexture() {
return texture;
}
-void CompositorGL::NotifyStart() {
+void CompositorGL::OnNotifyStart() {
started_ = true;
gl_context_->MakeCurrent(gl_surface_.get());
glViewport(0, 0, size().width(), size().height());
@@ -484,7 +484,7 @@ void CompositorGL::NotifyStart() {
// Do not clear in release: root layer is responsible for drawing every pixel.
}
-void CompositorGL::NotifyEnd() {
+void CompositorGL::OnNotifyEnd() {
DCHECK(started_);
gl_surface_->SwapBuffers();
started_ = false;
diff --git a/ui/gfx/compositor/compositor_gl.h b/ui/gfx/compositor/compositor_gl.h
index cee38c4..dc7ac8c 100644
--- a/ui/gfx/compositor/compositor_gl.h
+++ b/ui/gfx/compositor/compositor_gl.h
@@ -107,8 +107,8 @@ class COMPOSITOR_EXPORT CompositorGL : public Compositor {
private:
// Overridden from Compositor.
virtual Texture* CreateTexture() OVERRIDE;
- virtual void NotifyStart() OVERRIDE;
- virtual void NotifyEnd() OVERRIDE;
+ virtual void OnNotifyStart() OVERRIDE;
+ virtual void OnNotifyEnd() OVERRIDE;
virtual void Blur(const gfx::Rect& bounds) OVERRIDE;
// The GL context used for compositing.
diff --git a/ui/gfx/compositor/compositor_observer.h b/ui/gfx/compositor/compositor_observer.h
new file mode 100644
index 0000000..437ed5b
--- /dev/null
+++ b/ui/gfx/compositor/compositor_observer.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 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 UI_GFX_COMPOSITOR_COMPOSITOR_OBSERVER_H_
+#define UI_GFX_COMPOSITOR_COMPOSITOR_OBSERVER_H_
+#pragma once
+
+namespace ui {
+
+// A compositor observer is notified when compositing completes.
+class CompositorObserver {
+ public:
+ // Called when compositing completes.
+ virtual void OnCompositingEnded() = 0;
+
+ protected:
+ virtual ~CompositorObserver() {}
+};
+
+} // namespace ui
+
+#endif // UI_GFX_COMPOSITOR_COMPOSITOR_OBSERVER_H_
diff --git a/ui/gfx/compositor/compositor_stub.cc b/ui/gfx/compositor/compositor_stub.cc
new file mode 100644
index 0000000..ed7a4dd
--- /dev/null
+++ b/ui/gfx/compositor/compositor_stub.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 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 "ui/gfx/compositor/compositor.h"
+
+namespace ui {
+
+// static
+Compositor* Compositor::Create(CompositorDelegate* delegate,
+ gfx::AcceleratedWidget widget,
+ const gfx::Size& size) {
+ return NULL;
+}
+
+} // namespace ui
diff --git a/ui/gfx/compositor/compositor_win.cc b/ui/gfx/compositor/compositor_win.cc
index ae145a9..e07744a 100644
--- a/ui/gfx/compositor/compositor_win.cc
+++ b/ui/gfx/compositor/compositor_win.cc
@@ -102,11 +102,11 @@ class CompositorWin : public Compositor {
// Compositor:
virtual Texture* CreateTexture() OVERRIDE;
- virtual void NotifyStart() OVERRIDE;
- virtual void NotifyEnd() OVERRIDE;
virtual void Blur(const gfx::Rect& bounds) OVERRIDE;
protected:
+ virtual void OnNotifyStart() OVERRIDE;
+ virtual void OnNotifyEnd() OVERRIDE;
virtual void OnWidgetSizeChanged() OVERRIDE;
private:
@@ -387,7 +387,7 @@ Texture* CompositorWin::CreateTexture() {
return new ViewTexture(this, device_.get(), fx_.get());
}
-void CompositorWin::NotifyStart() {
+void CompositorWin::OnNotifyStart() {
ID3D10RenderTargetView* target_view = main_render_target_view_.get();
device_->OMSetRenderTargets(1, &target_view, depth_stencil_view_.get());
@@ -406,7 +406,7 @@ void CompositorWin::NotifyStart() {
device_->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
-void CompositorWin::NotifyEnd() {
+void CompositorWin::OnNotifyEnd() {
// Copy from main_render_target_view_| (where all are rendering was done) back
// to |dest_render_target_view_|.
ID3D10RenderTargetView* target_view = dest_render_target_view_.get();
diff --git a/ui/gfx/interpolated_transform.cc b/ui/gfx/interpolated_transform.cc
index 1f37f84..b2669bb 100644
--- a/ui/gfx/interpolated_transform.cc
+++ b/ui/gfx/interpolated_transform.cc
@@ -4,9 +4,21 @@
#include "ui/gfx/interpolated_transform.h"
+#include <cmath>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
#include "base/logging.h"
#include "ui/base/animation/tween.h"
+namespace {
+
+static const float EPSILON = 1e-6f;
+
+} // namespace
+
namespace ui {
///////////////////////////////////////////////////////////////////////////////
@@ -38,6 +50,61 @@ void InterpolatedTransform::SetChild(InterpolatedTransform* child) {
child_.reset(child);
}
+bool InterpolatedTransform::FactorTRS(const ui::Transform& transform,
+ gfx::Point* translation,
+ float* rotation,
+ gfx::Point3f* scale) {
+ const SkMatrix44& m = transform.matrix();
+ float m00 = m.get(0, 0);
+ float m01 = m.get(0, 1);
+ float m10 = m.get(1, 0);
+ float m11 = m.get(1, 1);
+
+ // A factorable 2D TRS matrix must be of the form:
+ // [ sx*cos_theta -(sy*sin_theta) 0 tx ]
+ // [ sx*sin_theta sy*cos_theta 0 ty ]
+ // [ 0 0 1 0 ]
+ // [ 0 0 0 1 ]
+ if (m.get(0, 2) != 0 ||
+ m.get(1, 2) != 0 ||
+ m.get(2, 0) != 0 ||
+ m.get(2, 1) != 0 ||
+ m.get(2, 2) != 1 ||
+ m.get(2, 3) != 0 ||
+ m.get(3, 0) != 0 ||
+ m.get(3, 1) != 0 ||
+ m.get(3, 2) != 0 ||
+ m.get(3, 3) != 1) {
+ return false;
+ }
+
+ float scale_x = sqrt(m00 * m00 + m10 * m10);
+ float scale_y = sqrt(m01 * m01 + m11 * m11);
+
+ if (scale_x == 0 || scale_y == 0)
+ return false;
+
+ float cos_theta = m00 / scale_x;
+ float sin_theta = m10 / scale_x;
+
+ if ((fabs(cos_theta - (m11 / scale_y))) > EPSILON ||
+ (fabs(sin_theta + (m01 / scale_y))) > EPSILON ||
+ (fabs(cos_theta*cos_theta + sin_theta*sin_theta - 1.0f) > EPSILON)) {
+ return false;
+ }
+
+ float radians = atan2(sin_theta, cos_theta);
+
+ if (translation)
+ *translation = gfx::Point(m.get(0, 3), m.get(1, 3));
+ if (rotation)
+ *rotation = radians * 180 / M_PI;
+ if (scale)
+ *scale = gfx::Point3f(scale_x, scale_y, 1.0f);
+
+ return true;
+}
+
inline float InterpolatedTransform::ValueBetween(float time,
float start_value,
float end_value) const {
@@ -94,15 +161,28 @@ ui::Transform InterpolatedRotation::InterpolateButDoNotCompose(float t) const {
// InterpolatedScale
//
-InterpolatedScale::InterpolatedScale(float start_scale,
- float end_scale)
+InterpolatedScale::InterpolatedScale(float start_scale, float end_scale)
+ : InterpolatedTransform(),
+ start_scale_(gfx::Point3f(start_scale, start_scale, start_scale)),
+ end_scale_(gfx::Point3f(end_scale, end_scale, end_scale)) {
+}
+
+InterpolatedScale::InterpolatedScale(float start_scale, float end_scale,
+ float start_time, float end_time)
+ : InterpolatedTransform(start_time, end_time),
+ start_scale_(gfx::Point3f(start_scale, start_scale, start_scale)),
+ end_scale_(gfx::Point3f(end_scale, end_scale, end_scale)) {
+}
+
+InterpolatedScale::InterpolatedScale(const gfx::Point3f& start_scale,
+ const gfx::Point3f& end_scale)
: InterpolatedTransform(),
start_scale_(start_scale),
end_scale_(end_scale) {
}
-InterpolatedScale::InterpolatedScale(float start_scale,
- float end_scale,
+InterpolatedScale::InterpolatedScale(const gfx::Point3f& start_scale,
+ const gfx::Point3f& end_scale,
float start_time,
float end_time)
: InterpolatedTransform(start_time, end_time),
@@ -114,9 +194,10 @@ InterpolatedScale::~InterpolatedScale() {}
ui::Transform InterpolatedScale::InterpolateButDoNotCompose(float t) const {
ui::Transform result;
- float interpolated_scale = ValueBetween(t, start_scale_, end_scale_);
+ float scale_x = ValueBetween(t, start_scale_.x(), end_scale_.x());
+ float scale_y = ValueBetween(t, start_scale_.y(), end_scale_.y());
// TODO(vollick) 3d xforms.
- result.SetScale(interpolated_scale, interpolated_scale);
+ result.SetScale(scale_x, scale_y);
return result;
}
@@ -196,7 +277,7 @@ InterpolatedTransformAboutPivot::InterpolateButDoNotCompose(float t) const {
if (transform_.get()) {
return transform_->Interpolate(t);
}
- return ui::Transform();
+ return Transform();
}
void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot,
@@ -216,4 +297,63 @@ void InterpolatedTransformAboutPivot::Init(const gfx::Point& pivot,
transform_.reset(pre_transform.release());
}
+InterpolatedTRSTransform::InterpolatedTRSTransform(
+ const ui::Transform& start_transform,
+ const ui::Transform& end_transform)
+ : InterpolatedTransform() {
+ Init(start_transform, end_transform);
+}
+
+InterpolatedTRSTransform::InterpolatedTRSTransform(
+ const ui::Transform& start_transform,
+ const ui::Transform& end_transform,
+ float start_time,
+ float end_time)
+ : InterpolatedTransform() {
+ Init(start_transform, end_transform);
+}
+
+InterpolatedTRSTransform::~InterpolatedTRSTransform() {}
+
+ui::Transform
+InterpolatedTRSTransform::InterpolateButDoNotCompose(float t) const {
+ if (transform_.get()) {
+ return transform_->Interpolate(t);
+ }
+ return Transform();
+}
+
+void InterpolatedTRSTransform::Init(const Transform& start_transform,
+ const Transform& end_transform) {
+ gfx::Point start_translation, end_translation;
+ gfx::Point3f start_scale, end_scale;
+ float start_degrees, end_degrees;
+ if (FactorTRS(start_transform,
+ &start_translation,
+ &start_degrees,
+ &start_scale) &&
+ FactorTRS(end_transform,
+ &end_translation,
+ &end_degrees,
+ &end_scale)) {
+ scoped_ptr<InterpolatedTranslation> translation(
+ new InterpolatedTranslation(start_translation, end_translation,
+ start_time(), end_time()));
+
+ scoped_ptr<InterpolatedScale> scale(
+ new InterpolatedScale(start_scale, end_scale,
+ start_time(), end_time()));
+
+ scoped_ptr<InterpolatedRotation> rotation(
+ new InterpolatedRotation(start_degrees, end_degrees,
+ start_time(), end_time()));
+
+ rotation->SetChild(translation.release());
+ scale->SetChild(rotation.release());
+ transform_.reset(scale.release());
+ } else {
+ transform_.reset(new InterpolatedConstantTransform(end_transform));
+ }
+}
+
} // namespace ui
diff --git a/ui/gfx/interpolated_transform.h b/ui/gfx/interpolated_transform.h
index b2220a8..9bc4bbb 100644
--- a/ui/gfx/interpolated_transform.h
+++ b/ui/gfx/interpolated_transform.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/point.h"
+#include "ui/gfx/point3.h"
#include "ui/gfx/transform.h"
namespace ui {
@@ -41,6 +42,11 @@ class UI_EXPORT InterpolatedTransform {
// This function takes ownership of the passed InterpolatedTransform.
void SetChild(InterpolatedTransform* child);
+ static bool FactorTRS(const ui::Transform& transform,
+ gfx::Point* translation,
+ float* rotation,
+ gfx::Point3f* scale);
+
protected:
// Calculates the interpolated transform without considering our child.
virtual ui::Transform InterpolateButDoNotCompose(float t) const = 0;
@@ -53,6 +59,9 @@ class UI_EXPORT InterpolatedTransform {
// it returns end_value.
float ValueBetween(float time, float start_value, float end_value) const;
+ float start_time() const { return start_time_; }
+ float end_time() const { return end_time_; }
+
private:
const float start_time_;
const float end_time_;
@@ -100,8 +109,12 @@ class UI_EXPORT InterpolatedRotation : public InterpolatedTransform {
class UI_EXPORT InterpolatedScale : public InterpolatedTransform {
public:
InterpolatedScale(float start_scale, float end_scale);
- InterpolatedScale(float start_scale,
- float end_scale,
+ InterpolatedScale(float start_scale, float end_scale,
+ float start_time, float end_time);
+ InterpolatedScale(const gfx::Point3f& start_scale,
+ const gfx::Point3f& end_scale);
+ InterpolatedScale(const gfx::Point3f& start_scale,
+ const gfx::Point3f& end_scale,
float start_time,
float end_time);
virtual ~InterpolatedScale();
@@ -110,8 +123,8 @@ class UI_EXPORT InterpolatedScale : public InterpolatedTransform {
virtual ui::Transform InterpolateButDoNotCompose(float t) const OVERRIDE;
private:
- const float start_scale_;
- const float end_scale_;
+ const gfx::Point3f start_scale_;
+ const gfx::Point3f end_scale_;
DISALLOW_COPY_AND_ASSIGN(InterpolatedScale);
};
@@ -181,7 +194,7 @@ class UI_EXPORT InterpolatedTransformAboutPivot : public InterpolatedTransform {
virtual ~InterpolatedTransformAboutPivot();
protected:
- virtual ui::Transform InterpolateButDoNotCompose(float t) const OVERRIDE;
+ virtual Transform InterpolateButDoNotCompose(float t) const OVERRIDE;
private:
void Init(const gfx::Point& pivot, InterpolatedTransform* transform);
@@ -191,6 +204,28 @@ class UI_EXPORT InterpolatedTransformAboutPivot : public InterpolatedTransform {
DISALLOW_COPY_AND_ASSIGN(InterpolatedTransformAboutPivot);
};
+class UI_EXPORT InterpolatedTRSTransform : public InterpolatedTransform {
+ public:
+ InterpolatedTRSTransform(const Transform& start_transform,
+ const Transform& end_transform);
+
+ InterpolatedTRSTransform(const Transform& start_transform,
+ const Transform& end_transform,
+ float start_time,
+ float end_time);
+
+ virtual ~InterpolatedTRSTransform();
+
+ protected:
+ virtual Transform InterpolateButDoNotCompose(float t) const OVERRIDE;
+
+ private:
+ void Init(const ui::Transform& start_transform,
+ const ui::Transform& end_transform);
+
+ scoped_ptr<InterpolatedTransform> transform_;
+};
+
} // namespace ui
#endif // UI_GFX_INTERPOLATED_TRANSFORM_H_
diff --git a/ui/gfx/interpolated_transform_unittest.cc b/ui/gfx/interpolated_transform_unittest.cc
index fa5debc..6c5627e 100644
--- a/ui/gfx/interpolated_transform_unittest.cc
+++ b/ui/gfx/interpolated_transform_unittest.cc
@@ -18,6 +18,16 @@ void CheckApproximatelyEqual(const ui::Transform& lhs,
}
}
+float NormalizeAngle(float angle) {
+ while (angle < 0.0f) {
+ angle += 360.0f;
+ }
+ while (angle > 360.0f) {
+ angle -= 360.0f;
+ }
+ return angle;
+}
+
} // namespace
TEST(InterpolatedTransformTest, InterpolatedRotation) {
@@ -36,9 +46,10 @@ TEST(InterpolatedTransformTest, InterpolatedRotation) {
}
TEST(InterpolatedTransformTest, InterpolatedScale) {
- ui::InterpolatedScale interpolated_scale(0, 100);
+ ui::InterpolatedScale interpolated_scale(gfx::Point3f(0, 0, 0),
+ gfx::Point3f(100, 100, 100));
ui::InterpolatedScale interpolated_scale_diff_start_end(
- 0, 100, 100, 200);
+ gfx::Point3f(0, 0, 0), gfx::Point3f(100, 100, 100), 100, 200);
for (int i = 0; i <= 100; ++i) {
ui::Transform scale;
@@ -90,7 +101,7 @@ TEST(InterpolatedTransformTest, InterpolatedScaleAboutPivot) {
gfx::Point above_pivot(100, 200);
ui::InterpolatedTransformAboutPivot interpolated_xform(
pivot,
- new ui::InterpolatedScale(1, 2));
+ new ui::InterpolatedScale(gfx::Point3f(1, 1, 1), gfx::Point3f(2, 2, 2)));
ui::Transform result = interpolated_xform.Interpolate(0.0f);
CheckApproximatelyEqual(ui::Transform(), result);
result = interpolated_xform.Interpolate(1.0f);
@@ -101,3 +112,28 @@ TEST(InterpolatedTransformTest, InterpolatedScaleAboutPivot) {
result.TransformPoint(above_pivot);
EXPECT_EQ(expected_result, above_pivot);
}
+
+TEST(InterpolatedTransformTest, FactorTRS) {
+ for (int degrees = 0; degrees < 360; ++degrees) {
+ // build a transformation matrix.
+ ui::Transform transform;
+ transform.SetScale(degrees + 1, 2 * degrees + 1);
+ transform.ConcatRotate(degrees);
+ transform.ConcatTranslate(degrees * 2, -degrees * 3);
+
+ // factor the matrix
+ gfx::Point translation;
+ float rotation;
+ gfx::Point3f scale;
+ bool success = ui::InterpolatedTransform::FactorTRS(transform,
+ &translation,
+ &rotation,
+ &scale);
+ EXPECT_TRUE(success);
+ EXPECT_FLOAT_EQ(translation.x(), degrees * 2);
+ EXPECT_FLOAT_EQ(translation.y(), -degrees * 3);
+ EXPECT_FLOAT_EQ(NormalizeAngle(rotation), degrees);
+ EXPECT_FLOAT_EQ(scale.x(), degrees + 1);
+ EXPECT_FLOAT_EQ(scale.y(), 2 * degrees + 1);
+ }
+}
diff --git a/views/paint_lock.cc b/views/paint_lock.cc
new file mode 100644
index 0000000..282c2c3
--- /dev/null
+++ b/views/paint_lock.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 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 "views/paint_lock.h"
+
+#include "views/view.h"
+
+namespace views {
+
+PaintLock::PaintLock(View* view) : view_(view) {
+ view_->set_painting_enabled(false);
+}
+
+PaintLock::~PaintLock() {
+ view_->set_painting_enabled(true);
+}
+
+} // namespace views
diff --git a/views/paint_lock.h b/views/paint_lock.h
new file mode 100644
index 0000000..7a6f9bb
--- /dev/null
+++ b/views/paint_lock.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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 VIEWS_PAINT_LOCK_H_
+#define VIEWS_PAINT_LOCK_H_
+#pragma once
+
+#include "base/basictypes.h"
+
+namespace views {
+
+class View;
+
+// Instances of PaintLock can be created to disable painting of the view
+// (compositing is not disabled). When the class is destroyed, painting is
+// re-enabled. This can be useful during operations like animations, that are
+// sensitive to costly paints, and during which only composting, not painting,
+// is required.
+class PaintLock {
+ public:
+ // The paint lock does not own the view. It is an error for the view to be
+ // destroyed before the lock.
+ PaintLock(View* view);
+ ~PaintLock();
+
+ private:
+ View* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintLock);
+};
+
+} // namespace views
+
+#endif // VIEWS_PAINT_LOCK_H_
diff --git a/views/view.cc b/views/view.cc
index 22cdeb2..fff2386 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
@@ -104,6 +105,7 @@ View::View()
parent_(NULL),
visible_(true),
enabled_(true),
+ painting_enabled_(true),
registered_for_visible_bounds_notification_(false),
clip_x_(0.0),
clip_y_(0.0),
@@ -680,7 +682,7 @@ void View::SchedulePaint() {
}
void View::SchedulePaintInRect(const gfx::Rect& rect) {
- if (!IsVisible())
+ if (!IsVisible() || !painting_enabled_)
return;
MarkLayerDirty();
@@ -688,7 +690,8 @@ void View::SchedulePaintInRect(const gfx::Rect& rect) {
}
void View::Paint(gfx::Canvas* canvas) {
- if (!IsVisible())
+ TRACE_EVENT0("View", "Paint");
+ if (!IsVisible() || !painting_enabled_)
return;
ScopedCanvas scoped_canvas(NULL);
@@ -1168,7 +1171,7 @@ void View::PaintComposite() {
}
void View::SchedulePaintInternal(const gfx::Rect& rect) {
- if (parent_ && parent_->IsVisible()) {
+ if (parent_ && parent_->IsVisible() && painting_enabled_) {
// Translate the requested paint rect to the parent's coordinate system
// then pass this notification up to the parent.
parent_->SchedulePaintInternal(ConvertRectToParent(rect));
diff --git a/views/view.h b/views/view.h
index c188531..a3e8151 100644
--- a/views/view.h
+++ b/views/view.h
@@ -1104,6 +1104,7 @@ class VIEWS_EXPORT View : public AcceleratorTarget {
friend class FocusManager;
friend class ViewStorage;
friend class Widget;
+ friend class PaintLock;
// Used to track a drag. RootView passes this into
// ProcessMousePressed/Dragged.
@@ -1229,6 +1230,11 @@ class VIEWS_EXPORT View : public AcceleratorTarget {
// Accelerated painting ------------------------------------------------------
+ // Disables painting during time critical operations. Used by PaintLock.
+ // TODO(vollick) Ideally, the widget would not dispatch paints into the
+ // hierarchy during time critical operations and this would not be needed.
+ void set_painting_enabled(bool enabled) { painting_enabled_ = enabled; }
+
// Returns true if this view should paint to layer.
bool ShouldPaintToLayer() const;
@@ -1353,6 +1359,9 @@ class VIEWS_EXPORT View : public AcceleratorTarget {
// Whether this view is enabled.
bool enabled_;
+ // Whether this view is painting.
+ bool painting_enabled_;
+
// Whether or not RegisterViewForVisibleBoundsNotification on the RootView
// has been invoked.
bool registered_for_visible_bounds_notification_;
diff --git a/views/views.gyp b/views/views.gyp
index 957c45f..d6e3145 100644
--- a/views/views.gyp
+++ b/views/views.gyp
@@ -307,6 +307,8 @@
'native_theme_delegate.h',
'native_theme_painter.cc',
'native_theme_painter.h',
+ 'paint_lock.cc',
+ 'paint_lock.h',
'painter.cc',
'painter.h',
'repeat_controller.cc',