diff options
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, °rees, 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', |