123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- // 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/accessibility/magnifier/fullscreen_magnifier_controller.h"
- #include "ash/display/display_util.h"
- #include "ash/host/root_window_transformer.h"
- #include "ash/shell.h"
- #include "ash/utility/transformer_util.h"
- #include "base/command_line.h"
- #include "base/memory/ptr_util.h"
- #include "base/system/sys_info.h"
- #include "ui/display/display.h"
- #include "ui/display/manager/display_manager.h"
- #include "ui/display/screen.h"
- #include "ui/gfx/geometry/insets.h"
- #include "ui/gfx/geometry/size_conversions.h"
- #include "ui/gfx/geometry/transform.h"
- namespace ash {
- namespace {
- // TODO(oshima): Transformers should be able to adjust itself
- // when the device scale factor is changed, instead of
- // precalculating the transform using fixed value.
- // Creates rotation transform for |root_window| to |new_rotation|. This will
- // call |CreateRotationTransform()|, the |old_rotation| will implicitly be
- // |display::Display::ROTATE_0|.
- gfx::Transform CreateRootWindowRotationTransform(
- const display::Display& display) {
- gfx::SizeF size(display.GetSizeInPixel());
- // Use SizeF so that the origin of translated layer will be
- // aligned when scaled back at pixels.
- size.Scale(1.f / display.device_scale_factor());
- return CreateRotationTransform(display::Display::ROTATE_0,
- display.panel_rotation(), size);
- }
- gfx::Transform CreateInsetsTransform(const gfx::Insets& insets,
- float device_scale_factor) {
- 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);
- }
- return transform;
- }
- // Returns a transform with rotation adjusted |insets_in_pixel|. The transform
- // is applied to the root window so that |insets_in_pixel| looks correct after
- // the rotation applied at the output.
- gfx::Transform CreateReverseRotatedInsetsTransform(
- display::Display::Rotation rotation,
- const gfx::Insets& insets_in_pixel,
- float device_scale_factor) {
- float x_offset = 0;
- float y_offset = 0;
- switch (rotation) {
- case display::Display::ROTATE_0:
- x_offset = insets_in_pixel.left();
- y_offset = insets_in_pixel.top();
- break;
- case display::Display::ROTATE_90:
- x_offset = insets_in_pixel.top();
- y_offset = insets_in_pixel.right();
- break;
- case display::Display::ROTATE_180:
- x_offset = insets_in_pixel.right();
- y_offset = insets_in_pixel.bottom();
- break;
- case display::Display::ROTATE_270:
- x_offset = insets_in_pixel.bottom();
- y_offset = insets_in_pixel.left();
- break;
- }
- gfx::Transform transform;
- if (x_offset != 0 || y_offset != 0) {
- x_offset /= device_scale_factor;
- y_offset /= device_scale_factor;
- transform.Translate(x_offset, y_offset);
- }
- return transform;
- }
- // RootWindowTransformer for ash environment.
- class AshRootWindowTransformer : public RootWindowTransformer {
- public:
- AshRootWindowTransformer(const display::Display& display) {
- initial_root_bounds_ = gfx::Rect(display.size());
- display::DisplayManager* display_manager = Shell::Get()->display_manager();
- display::ManagedDisplayInfo info =
- display_manager->GetDisplayInfo(display.id());
- host_insets_ = info.GetOverscanInsetsInPixel();
- gfx::Transform insets_and_rotation_transform =
- CreateInsetsTransform(host_insets_, display.device_scale_factor()) *
- CreateRootWindowRotationTransform(display);
- transform_ = insets_and_rotation_transform;
- insets_and_scale_transform_ = CreateReverseRotatedInsetsTransform(
- display.panel_rotation(), host_insets_, display.device_scale_factor());
- FullscreenMagnifierController* magnifier =
- Shell::Get()->fullscreen_magnifier_controller();
- if (magnifier) {
- gfx::Transform magnifier_scale = magnifier->GetMagnifierTransform();
- transform_ *= magnifier_scale;
- insets_and_scale_transform_ *= magnifier_scale;
- }
- CHECK(transform_.GetInverse(&invert_transform_));
- CHECK(insets_and_rotation_transform.GetInverse(
- &root_window_bounds_transform_));
- root_window_bounds_transform_.Scale(1.f / display.device_scale_factor(),
- 1.f / display.device_scale_factor());
- initial_host_size_ = info.bounds_in_native().size();
- }
- AshRootWindowTransformer(const AshRootWindowTransformer&) = delete;
- AshRootWindowTransformer& operator=(const AshRootWindowTransformer&) = delete;
- // aura::RootWindowTransformer overrides:
- gfx::Transform GetTransform() const override { return transform_; }
- gfx::Transform GetInverseTransform() const override {
- return invert_transform_;
- }
- gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
- if (base::SysInfo::IsRunningOnChromeOS())
- return initial_root_bounds_;
- // If we're running on linux desktop for dev purpose, the host window
- // may be updated to new size. Recompute the root window bounds based
- // on the host size if the host size changed.
- if (initial_host_size_ == host_size)
- return initial_root_bounds_;
- gfx::RectF new_bounds = gfx::RectF(gfx::SizeF(host_size));
- new_bounds.Inset(gfx::InsetsF(host_insets_));
- root_window_bounds_transform_.TransformRect(&new_bounds);
- // Root window origin will be (0,0) except during bounds changes.
- // Set to exactly zero to avoid rounding issues.
- // 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()));
- }
- gfx::Insets GetHostInsets() const override { return host_insets_; }
- gfx::Transform GetInsetsAndScaleTransform() const override {
- return insets_and_scale_transform_;
- }
- private:
- ~AshRootWindowTransformer() override = default;
- 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 the root window. It is the composition of the following transforms
- // - inverse of insets. Insets position the content area within the display.
- // - inverse of rotation. Rotation changes orientation of the content area.
- // - inverse of device scale. Scaling up content shrinks the content area.
- //
- // Insets also shrink the content area but this happens prior to applying the
- // transformation in GetRootWindowBounds().
- //
- // Magnification does not affect the window size. Content is clipped in this
- // case, but the magnifier allows panning to reach clipped areas.
- //
- // The transforms are inverted because GetTransform() is the transform from
- // root window coordinates to host coordinates, but this transform is used in
- // the reverse direction (derives root window bounds from display bounds).
- gfx::Transform root_window_bounds_transform_;
- gfx::Insets host_insets_;
- gfx::Transform insets_and_scale_transform_;
- gfx::Rect initial_root_bounds_;
- gfx::Size initial_host_size_;
- };
- // 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 RootWindowTransformer {
- public:
- MirrorRootWindowTransformer(
- const display::ManagedDisplayInfo& source_display_info,
- const display::ManagedDisplayInfo& mirror_display_info) {
- root_bounds_ =
- gfx::Rect(source_display_info.GetSizeInPixelWithPanelOrientation());
- display::Display::Rotation active_root_rotation =
- source_display_info.GetActiveRotation();
- const bool should_undo_rotation = ShouldUndoRotationForMirror();
- gfx::Transform rotation_transform;
- if (should_undo_rotation) {
- // Calculate the transform to undo the rotation and apply it to the
- // source display. Use GetActiveRotation() because |source_bounds_|
- // includes panel rotation and we only need to revert active rotation.
- rotation_transform = CreateRotationTransform(
- source_display_info.GetActiveRotation(), display::Display::ROTATE_0,
- gfx::SizeF(root_bounds_.size()));
- gfx::RectF rotated_bounds(root_bounds_);
- rotation_transform.TransformRect(&rotated_bounds);
- root_bounds_ = gfx::ToNearestRect(rotated_bounds);
- active_root_rotation = display::Display::ROTATE_0;
- }
- gfx::Rect mirror_display_rect =
- gfx::Rect(mirror_display_info.bounds_in_native().size());
- // When logical rotation is 90 or 270 degree, transpose is needed to apply
- // reverse rotation to `root_bounds_` and `mirror_display_rect` to exclude
- // the rotation. This is because the rotation happens at viz output and
- // `transform_` needs to be calculated without the rotation.
- // E.g. host native size 1600x1200. Rotation 90 degree. `transform_` needs
- // to fit 1200x1600 rather than 1600x1200.
- const bool need_transpose =
- active_root_rotation == display::Display::ROTATE_90 ||
- active_root_rotation == display::Display::ROTATE_270;
- if (need_transpose) {
- root_bounds_.Transpose();
- mirror_display_rect.Transpose();
- }
- bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
- root_bounds_.height() * mirror_display_rect.width();
- if (letterbox) {
- 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;
- int margin = static_cast<int>((mirror_display_rect.height() -
- root_bounds_.height() * inverted_scale) /
- 2);
- insets_ = gfx::Insets::TLBR(0, margin, 0, margin);
- transform_.Translate(0, margin);
- transform_.Scale(inverted_scale, inverted_scale);
- } else {
- float mirror_scale_ratio =
- (static_cast<float>(root_bounds_.height()) /
- static_cast<float>(mirror_display_rect.height()));
- float inverted_scale = 1.0f / mirror_scale_ratio;
- int margin = static_cast<int>((mirror_display_rect.width() -
- root_bounds_.width() * inverted_scale) /
- 2);
- insets_ = gfx::Insets::TLBR(margin, 0, margin, 0);
- transform_.Translate(margin, 0);
- transform_.Scale(inverted_scale, inverted_scale);
- }
- }
- MirrorRootWindowTransformer(const MirrorRootWindowTransformer&) = delete;
- MirrorRootWindowTransformer& operator=(const MirrorRootWindowTransformer&) =
- delete;
- // aura::RootWindowTransformer overrides:
- gfx::Transform GetTransform() const override { return transform_; }
- gfx::Transform GetInverseTransform() const override {
- gfx::Transform invert;
- CHECK(transform_.GetInverse(&invert));
- return invert;
- }
- gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
- return root_bounds_;
- }
- gfx::Insets GetHostInsets() const override { return insets_; }
- gfx::Transform GetInsetsAndScaleTransform() const override {
- return transform_;
- }
- private:
- ~MirrorRootWindowTransformer() override = default;
- gfx::Transform transform_;
- gfx::Rect root_bounds_;
- gfx::Insets insets_;
- };
- class PartialBoundsRootWindowTransformer : public RootWindowTransformer {
- public:
- PartialBoundsRootWindowTransformer(const gfx::Rect& screen_bounds,
- const display::Display& display) {
- const display::DisplayManager* display_manager =
- Shell::Get()->display_manager();
- display::ManagedDisplayInfo display_info =
- display_manager->GetDisplayInfo(display.id());
- // Physical root bounds.
- root_bounds_ = gfx::Rect(display_info.bounds_in_native().size());
- display::Display::Rotation active_root_rotation =
- display_info.GetActiveRotation();
- const bool need_transpose =
- active_root_rotation == display::Display::ROTATE_90 ||
- active_root_rotation == display::Display::ROTATE_270;
- if (need_transpose)
- root_bounds_.Transpose();
- // |screen_bounds| is the unified desktop logical bounds.
- // Calculate the unified height scale value, and apply the same scale on the
- // row physical height to get the row logical height.
- display::Display unified_display =
- display::Screen::GetScreen()->GetPrimaryDisplay();
- const int unified_physical_height =
- unified_display.GetSizeInPixel().height();
- const int unified_logical_height = screen_bounds.height();
- const float unified_height_scale =
- static_cast<float>(unified_logical_height) / unified_physical_height;
- const int row_index =
- display_manager->GetMirroringDisplayRowIndexInUnifiedMatrix(
- display.id());
- const int row_physical_height =
- display_manager->GetUnifiedDesktopRowMaxHeight(row_index);
- const int row_logical_height = row_physical_height * unified_height_scale;
- const float dsf = unified_display.device_scale_factor();
- const float scale = root_bounds_.height() / (dsf * row_logical_height);
- transform_.Scale(scale, scale);
- transform_.Translate(-SkIntToScalar(display.bounds().x()),
- -SkIntToScalar(display.bounds().y()));
- // Scaling using physical root bounds here, because rotation is applied
- // before device_scale_factor is applied.
- gfx::Transform rotation = CreateRotationTransform(
- display::Display::ROTATE_0, display.panel_rotation(),
- gfx::SizeF(root_bounds_.size()));
- CHECK((rotation * transform_).GetInverse(&invert_transform_));
- }
- PartialBoundsRootWindowTransformer(
- const PartialBoundsRootWindowTransformer&) = delete;
- PartialBoundsRootWindowTransformer& operator=(
- const PartialBoundsRootWindowTransformer&) = delete;
- // RootWindowTransformer:
- gfx::Transform GetTransform() const override { return transform_; }
- gfx::Transform GetInverseTransform() const override {
- return invert_transform_;
- }
- gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
- return root_bounds_;
- }
- gfx::Insets GetHostInsets() const override { return gfx::Insets(); }
- gfx::Transform GetInsetsAndScaleTransform() const override {
- return transform_;
- }
- private:
- ~PartialBoundsRootWindowTransformer() override = default;
- gfx::Transform transform_;
- gfx::Transform invert_transform_;
- gfx::Rect root_bounds_;
- };
- } // namespace
- std::unique_ptr<RootWindowTransformer> CreateRootWindowTransformerForDisplay(
- const display::Display& display) {
- return base::WrapUnique<RootWindowTransformer>(
- new AshRootWindowTransformer(display));
- }
- std::unique_ptr<RootWindowTransformer>
- CreateRootWindowTransformerForMirroredDisplay(
- const display::ManagedDisplayInfo& source_display_info,
- const display::ManagedDisplayInfo& mirror_display_info) {
- return base::WrapUnique<RootWindowTransformer>(
- new MirrorRootWindowTransformer(source_display_info,
- mirror_display_info));
- }
- std::unique_ptr<RootWindowTransformer>
- CreateRootWindowTransformerForUnifiedDesktop(const gfx::Rect& screen_bounds,
- const display::Display& display) {
- return base::WrapUnique<RootWindowTransformer>(
- new PartialBoundsRootWindowTransformer(screen_bounds, display));
- }
- } // namespace ash
|