Commit e4fcffa1 authored by Mitsuru Oshima's avatar Mitsuru Oshima Committed by Commit Bot

Fix rotation transform to avoid subpixel origin

Rotation transform should be constructed
so that when it is scaled, it should not lead to
subpixel origin.

Bug: 869090
Test: Covered by unittest. Also tested on a device
Change-Id: I5bc0c0885350e0cbc10fe23f8300cbf9b4492449
Reviewed-on: https://chromium-review.googlesource.com/1184144Reviewed-by: default avatarMalay Keshav <malaykeshav@chromium.org>
Commit-Queue: Mitsuru Oshima (OOO) <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585078}
parent 07be93b6
......@@ -36,8 +36,12 @@ gfx::Transform CreateRootWindowRotationTransform(
const display::Display& display) {
display::ManagedDisplayInfo info =
Shell::Get()->display_manager()->GetDisplayInfo(display.id());
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,
info.GetActiveRotation(), display.bounds());
info.GetActiveRotation(), size);
}
gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets,
......@@ -151,9 +155,9 @@ class MirrorRootWindowTransformer : public RootWindowTransformer {
if (should_undo_rotation) {
// Calculate the transform to undo the rotation and apply it to the
// source display.
rotation_transform =
CreateRotationTransform(source_display_info.GetActiveRotation(),
display::Display::ROTATE_0, root_bounds_);
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);
......
......@@ -20,6 +20,7 @@
#include "ui/aura/env.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tracker.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h"
......@@ -32,6 +33,7 @@
#include "ui/events/event_handler.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/views/widget/widget.h"
namespace ash {
......@@ -285,6 +287,63 @@ TEST_F(RootWindowTransformersTest, ScaleAndMagnify) {
Shell::Get()->RemovePreTargetHandler(&event_handler);
}
// Make sure the origin of rotated root layer is aligned with pixels
// on 2.25 scale factor device so that HW overlay kicks in.
// https://crbug.com/869090.
TEST_F(RootWindowTransformersTest, OriginAlignmentWithFractionalScale) {
auto* host_window = Shell::GetPrimaryRootWindow()->GetHost()->window();
EXPECT_EQ(Shell::GetPrimaryRootWindow(), host_window);
float device_scale_factor = 2.25f;
gfx::Transform scale_transform;
scale_transform.matrix().set3x3(device_scale_factor, 0, 0, 0,
device_scale_factor, 0, 0, 0, 1);
gfx::Transform invert_transform;
invert_transform.matrix().set3x3(1.0f / device_scale_factor, 0, 0, 0,
1.0f / device_scale_factor, 0, 0, 0, 1);
{
// Rotate 90 degree to right.
UpdateDisplay("3000x2000*2.25/r");
// The size of the scaled layer.
gfx::RectF tmp(1998, 2999);
// Creates a transform that can be applied to already scaled layer.
gfx::Transform transform(invert_transform);
transform.ConcatTransform(host_window->layer()->transform());
transform.ConcatTransform(scale_transform);
transform.TransformRect(&tmp);
EXPECT_EQ(gfx::SizeF(2999, 1998), tmp.size());
EXPECT_TRUE(gfx::IsNearestRectWithinDistance(tmp, 0.01f));
}
{
// Upside Down.
UpdateDisplay("3000x2000*2.25/u");
gfx::RectF tmp(2999, 1998);
gfx::Transform transform(invert_transform);
transform.ConcatTransform(host_window->layer()->transform());
transform.ConcatTransform(scale_transform);
transform.TransformRect(&tmp);
EXPECT_EQ(gfx::SizeF(2999, 1998), tmp.size());
EXPECT_TRUE(gfx::IsNearestRectWithinDistance(tmp, 0.01f));
}
{
// Rotate 90 degree to left.
UpdateDisplay("3000x2000*2.25/l");
gfx::RectF tmp(1998, 2999);
gfx::Transform transform(invert_transform);
transform.ConcatTransform(host_window->layer()->transform());
transform.ConcatTransform(scale_transform);
transform.TransformRect(&tmp);
EXPECT_EQ(gfx::SizeF(2999, 1998), tmp.size());
EXPECT_TRUE(gfx::IsNearestRectWithinDistance(tmp, 0.01f));
}
}
TEST_F(RootWindowTransformersTest, TouchScaleAndMagnify) {
TestEventHandler event_handler;
Shell::Get()->AddPreTargetHandler(&event_handler);
......
......@@ -12,6 +12,8 @@
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
......
......@@ -33,7 +33,7 @@
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/transform_util.h"
#include "ui/wm/core/window_util.h"
......@@ -115,7 +115,8 @@ gfx::Transform CreateScreenRotationOldLayerTransformForDisplay(
display::Display::Rotation new_rotation,
const display::Display& display) {
gfx::Transform inverse;
CHECK(CreateRotationTransform(old_rotation, new_rotation, display.bounds())
CHECK(CreateRotationTransform(old_rotation, new_rotation,
gfx::SizeF(display.size()))
.GetInverse(&inverse));
return inverse;
}
......
......@@ -7,9 +7,11 @@
#include <cmath>
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/transform.h"
namespace ash {
namespace {
// Round near zero value to zero.
void RoundNearZero(gfx::Transform* transform) {
......@@ -23,28 +25,29 @@ void RoundNearZero(gfx::Transform* transform) {
}
}
} // namespace
gfx::Transform CreateRotationTransform(display::Display::Rotation old_rotation,
display::Display::Rotation new_rotation,
const gfx::Rect& rect_to_rotate) {
const gfx::SizeF& size_to_rotate) {
const int rotation_angle = 90 * (((new_rotation - old_rotation) + 4) % 4);
gfx::Transform rotate;
switch (rotation_angle) {
case 0:
break;
case 90:
rotate.Translate(rect_to_rotate.height(), 0);
rotate.Translate(size_to_rotate.height(), 0);
rotate.Rotate(90);
break;
case 180:
rotate.Translate(rect_to_rotate.width(), rect_to_rotate.height());
rotate.Translate(size_to_rotate.width(), size_to_rotate.height());
rotate.Rotate(180);
break;
case 270:
rotate.Translate(0, rect_to_rotate.width());
rotate.Translate(0, size_to_rotate.width());
rotate.Rotate(270);
break;
}
RoundNearZero(&rotate);
return rotate;
}
......
......@@ -9,17 +9,18 @@
#include "ui/display/display.h"
namespace gfx {
class SizeF;
class Transform;
}
namespace ash {
// Creates rotation transform that rotates the |rect_to_rotate| from
// Creates rotation transform that rotates the |size_to_rotate| from
// |old_rotation| to |new_rotation|.
ASH_EXPORT gfx::Transform CreateRotationTransform(
display::Display::Rotation old_rotation,
display::Display::Rotation new_rotation,
const gfx::Rect& rect_to_rotate);
const gfx::SizeF& size_to_rotate);
} // namespace ash
......
......@@ -269,9 +269,7 @@ void Display::SetScaleAndBounds(float device_scale_factor,
1.0f / device_scale_factor_),
gfx::ScaleToFlooredSize(bounds_in_pixel.size(),
1.0f / device_scale_factor_));
#if defined(OS_ANDROID)
size_in_pixels_ = bounds_in_pixel.size();
#endif // defined(OS_ANDROID)
UpdateWorkAreaFromInsets(insets);
}
......@@ -300,7 +298,6 @@ void Display::UpdateWorkAreaFromInsets(const gfx::Insets& insets) {
}
gfx::Size Display::GetSizeInPixel() const {
// TODO(oshima): This should always use size_in_pixels_.
if (!size_in_pixels_.IsEmpty())
return size_in_pixels_;
return gfx::ScaleToFlooredSize(size(), device_scale_factor_);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment