| Index: ash/display/root_window_transformers.cc
|
| diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..da5c3975e2c58afdfaa36bcd502e61ea54d5ae43
|
| --- /dev/null
|
| +++ b/ash/display/root_window_transformers.cc
|
| @@ -0,0 +1,276 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ash/display/root_window_transformers.h"
|
| +
|
| +#include <cmath>
|
| +
|
| +#include "ash/display/display_info.h"
|
| +#include "ash/display/display_manager.h"
|
| +#include "ash/magnifier/magnification_controller.h"
|
| +#include "ash/shell.h"
|
| +#include "base/basictypes.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "third_party/skia/include/utils/SkMatrix44.h"
|
| +#include "ui/aura/root_window.h"
|
| +#include "ui/aura/root_window_transformer.h"
|
| +#include "ui/aura/window_property.h"
|
| +#include "ui/compositor/dip_util.h"
|
| +#include "ui/gfx/display.h"
|
| +#include "ui/gfx/insets.h"
|
| +#include "ui/gfx/size_conversions.h"
|
| +#include "ui/gfx/transform.h"
|
| +#include "ui/gfx/transform.h"
|
| +
|
| +DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation);
|
| +
|
| +namespace ash {
|
| +namespace internal {
|
| +namespace {
|
| +
|
| +DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey,
|
| + gfx::Display::ROTATE_0);
|
| +
|
| +// Round near zero value to zero.
|
| +void RoundNearZero(gfx::Transform* transform) {
|
| + const float kEpsilon = 0.001f;
|
| + SkMatrix44& matrix = transform->matrix();
|
| + for (int x = 0; x < 4; ++x) {
|
| + for (int y = 0; y < 4; ++y) {
|
| + if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon)
|
| + matrix.set(x, y, SkFloatToMScalar(0.0f));
|
| + }
|
| + }
|
| +}
|
| +
|
| +gfx::Transform CreateRotationTransform(aura::RootWindow* root_window,
|
| + const gfx::Display& display) {
|
| + DisplayInfo info =
|
| + Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
|
| +
|
| + // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade)
|
| +#if defined(OS_WIN)
|
| + // Windows 8 bots refused to resize the host window, and
|
| + // updating the transform results in incorrectly resizing
|
| + // the root window. Don't apply the transform unless
|
| + // necessary so that unit tests pass on win8 bots.
|
| + if (info.rotation() == root_window->GetProperty(kRotationPropertyKey))
|
| + return gfx::Transform();
|
| + root_window->SetProperty(kRotationPropertyKey, info.rotation());
|
| +#endif
|
| +
|
| + gfx::Transform rotate;
|
| + // The origin is (0, 0), so the translate width/height must be reduced by
|
| + // 1 pixel.
|
| + float one_pixel = 1.0f / display.device_scale_factor();
|
| + switch (info.rotation()) {
|
| + case gfx::Display::ROTATE_0:
|
| + break;
|
| + case gfx::Display::ROTATE_90:
|
| + rotate.Translate(display.bounds().height() - one_pixel, 0);
|
| + rotate.Rotate(90);
|
| + break;
|
| + case gfx::Display::ROTATE_270:
|
| + rotate.Translate(0, display.bounds().width() - one_pixel);
|
| + rotate.Rotate(270);
|
| + break;
|
| + case gfx::Display::ROTATE_180:
|
| + rotate.Translate(display.bounds().width() - one_pixel,
|
| + display.bounds().height() - one_pixel);
|
| + rotate.Rotate(180);
|
| + break;
|
| + }
|
| +
|
| + RoundNearZero(&rotate);
|
| + return rotate;
|
| +}
|
| +
|
| +gfx::Transform CreateMagnifierTransform(aura::RootWindow* root_window) {
|
| + MagnificationController* magnifier =
|
| + Shell::GetInstance()->magnification_controller();
|
| + float magnifier_scale = 1.f;
|
| + gfx::Point magnifier_offset;
|
| + if (magnifier && magnifier->IsEnabled()) {
|
| + magnifier_scale = magnifier->GetScale();
|
| + magnifier_offset = magnifier->GetWindowPosition();
|
| + }
|
| + gfx::Transform transform;
|
| + if (magnifier_scale != 1.f) {
|
| + transform.Scale(magnifier_scale, magnifier_scale);
|
| + transform.Translate(-magnifier_offset.x(), -magnifier_offset.y());
|
| + }
|
| + return transform;
|
| +}
|
| +
|
| +gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets,
|
| + float device_scale_factor,
|
| + float ui_scale) {
|
| + gfx::Transform transform;
|
| + if (insets.top() != 0 || insets.left() != 0) {
|
| + float x_offset = insets.left() / device_scale_factor;
|
| + float y_offset = insets.top() / device_scale_factor;
|
| + transform.Translate(x_offset, y_offset);
|
| + }
|
| + float inverted_scale = 1.0f / ui_scale;
|
| + transform.Scale(inverted_scale, inverted_scale);
|
| + return transform;
|
| +}
|
| +
|
| +gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window,
|
| + const gfx::Display& display) {
|
| + DisplayInfo info =
|
| + Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
|
| + return CreateInsetsAndScaleTransform(
|
| + info.GetOverscanInsetsInPixel(),
|
| + ui::GetDeviceScaleFactor(root_window->layer()),
|
| + info.ui_scale());
|
| +}
|
| +
|
| +// RootWindowTransformer for ash environment.
|
| +class AshRootWindowTransformer : public aura::RootWindowTransformer {
|
| + public:
|
| + AshRootWindowTransformer(aura::RootWindow* root,
|
| + const gfx::Display& display)
|
| + : root_window_(root) {
|
| + root_window_bounds_transform_ =
|
| + CreateOverscanAndUIScaleTransform(root, display) *
|
| + CreateRotationTransform(root, display);
|
| + transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root);
|
| + CHECK(transform_.GetInverse(&invert_transform_));
|
| +
|
| + DisplayInfo info = Shell::GetInstance()->display_manager()->
|
| + GetDisplayInfo(display.id());
|
| + root_window_ui_scale_ = info.ui_scale();
|
| + host_insets_ = info.GetOverscanInsetsInPixel();
|
| + MagnificationController* magnifier =
|
| + Shell::GetInstance()->magnification_controller();
|
| +
|
| + bool scaled = (root_window_ui_scale_ != 1.f) ||
|
| + (magnifier && magnifier->GetScale() != 1.f);
|
| + root_window_->layer()->SetForceRenderSurface(scaled);
|
| + }
|
| +
|
| + // aura::RootWindowTransformer overrides:
|
| + virtual gfx::Transform GetTransform() const OVERRIDE {
|
| + return transform_;
|
| + }
|
| + virtual gfx::Transform GetInverseTransform() const OVERRIDE {
|
| + return invert_transform_;
|
| + }
|
| + virtual gfx::Rect GetRootWindowBounds(
|
| + const gfx::Size& host_size) const OVERRIDE {
|
| + gfx::Rect bounds(host_size);
|
| + bounds.Inset(host_insets_);
|
| + bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
|
| + gfx::RectF new_bounds(bounds);
|
| + root_window_bounds_transform_.TransformRect(&new_bounds);
|
| + // Apply |root_window_scale_| twice as the downscaling
|
| + // is already applied once in |SetTransformInternal()|.
|
| + // TODO(oshima): This is a bit ugly. Consider specifying
|
| + // the pseudo host resolution instead.
|
| + new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
|
| + // Ignore the origin because RootWindow's insets are handled by
|
| + // the transform.
|
| + // Floor the size because the bounds is no longer aligned to
|
| + // backing pixel when |root_window_scale_| is specified
|
| + // (850 height at 1.25 scale becomes 1062.5 for example.)
|
| + return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
|
| + }
|
| +
|
| + virtual gfx::Insets GetHostInsets() const OVERRIDE {
|
| + return host_insets_;
|
| + }
|
| +
|
| + private:
|
| + virtual ~AshRootWindowTransformer() {}
|
| +
|
| + aura::RootWindow* root_window_;
|
| + gfx::Transform transform_;
|
| +
|
| + // The accurate representation of the inverse of the |transform_|.
|
| + // This is used to avoid computation error caused by
|
| + // |gfx::Transform::GetInverse|.
|
| + gfx::Transform invert_transform_;
|
| +
|
| + // The transform of the root window bounds. This is used to calculate
|
| + // the size of root window.
|
| + gfx::Transform root_window_bounds_transform_;
|
| +
|
| + // The scale of the root window. This is used to expand the
|
| + // area of the root window (useful in HighDPI display).
|
| + // Note that this should not be confused with the device scale
|
| + // factor, which specfies the pixel density of the display.
|
| + float root_window_ui_scale_;
|
| +
|
| + gfx::Insets host_insets_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer);
|
| +};
|
| +
|
| +// RootWindowTransformer for mirror root window. We simply copy the
|
| +// texture (bitmap) of the source display into the mirror window, so
|
| +// the root window bounds is the same as the source display's
|
| +// pixel size (excluding overscan insets).
|
| +class MirrorRootWindowTransformer : public aura::RootWindowTransformer {
|
| + public:
|
| + MirrorRootWindowTransformer(const DisplayInfo& source_display_info,
|
| + const DisplayInfo& mirror_display_info) {
|
| + root_bounds_ = gfx::Rect(source_display_info.bounds_in_pixel().size());
|
| + gfx::Rect mirror_display_rect =
|
| + gfx::Rect(mirror_display_info.bounds_in_pixel().size());
|
| +
|
| + // TODO(oshima): Insets & scale has to be adjusted so that
|
| + // 1) it does letterbox/pillarbox to adjust aspect ratio
|
| + // 2) visible area excluding insets are correctly mapped
|
| + // to the other display's visible area.
|
| + float mirror_scale_ratio =
|
| + (static_cast<float>(root_bounds_.width()) /
|
| + static_cast<float>(mirror_display_rect.width()));
|
| + float inverted_scale = 1.0f / mirror_scale_ratio;
|
| + transform_.Scale(inverted_scale, inverted_scale);
|
| + }
|
| +
|
| + // aura::RootWindowTransformer overrides:
|
| + virtual gfx::Transform GetTransform() const OVERRIDE {
|
| + return transform_;
|
| + }
|
| + virtual gfx::Transform GetInverseTransform() const OVERRIDE {
|
| + gfx::Transform invert;
|
| + CHECK(transform_.GetInverse(&invert));
|
| + return invert;
|
| + }
|
| + virtual gfx::Rect GetRootWindowBounds(
|
| + const gfx::Size& host_size) const OVERRIDE {
|
| + return root_bounds_;
|
| + }
|
| + virtual gfx::Insets GetHostInsets() const OVERRIDE {
|
| + return gfx::Insets();
|
| + }
|
| +
|
| + private:
|
| + virtual ~MirrorRootWindowTransformer() {}
|
| +
|
| + gfx::Transform transform_;
|
| + gfx::Rect root_bounds_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay(
|
| + aura::RootWindow* root,
|
| + const gfx::Display& display) {
|
| + return new AshRootWindowTransformer(root, display);
|
| +}
|
| +
|
| +aura::RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
|
| + const DisplayInfo& source_display_info,
|
| + const DisplayInfo& mirror_display_info) {
|
| + return new MirrorRootWindowTransformer(source_display_info,
|
| + mirror_display_info);
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace ash
|
|
|