diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-25 04:31:19 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-25 04:31:19 +0000 |
commit | f958054738592c984e713a2582ac66d0e9bd5b4c (patch) | |
tree | 6b77e3edfeb2284ee77154b79f0ef2523ceaddef | |
parent | 0847a72a829a980801b75b1722c1a03847cd8e4f (diff) | |
download | chromium_src-f958054738592c984e713a2582ac66d0e9bd5b4c.zip chromium_src-f958054738592c984e713a2582ac66d0e9bd5b4c.tar.gz chromium_src-f958054738592c984e713a2582ac66d0e9bd5b4c.tar.bz2 |
Supports screen rotation / ui-scaling in snapshot_aura.cc
BUG=235007,236370
TEST=covered by the new tests
R=oshima@chromium.org, sky@chromium.org, backer@chromium.org
Review URL: https://chromiumcodereview.appspot.com/15160006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202268 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/aura/test/test_screen.cc | 44 | ||||
-rw-r--r-- | ui/aura/test/test_screen.h | 8 | ||||
-rw-r--r-- | ui/compositor/compositor.gyp | 4 | ||||
-rw-r--r-- | ui/snapshot/snapshot.gyp | 16 | ||||
-rw-r--r-- | ui/snapshot/snapshot_aura.cc | 42 | ||||
-rw-r--r-- | ui/snapshot/snapshot_aura_unittest.cc | 222 | ||||
-rw-r--r-- | ui/snapshot/test/run_all_unittests.cc | 14 |
7 files changed, 336 insertions, 14 deletions
diff --git a/ui/aura/test/test_screen.cc b/ui/aura/test/test_screen.cc index 69bf767..16afea4 100644 --- a/ui/aura/test/test_screen.cc +++ b/ui/aura/test/test_screen.cc @@ -46,6 +46,46 @@ void TestScreen::SetDeviceScaleFactor(float device_scale_factor) { root_window_->OnHostResized(bounds_in_pixel.size()); } +void TestScreen::SetDisplayRotation(gfx::Display::Rotation rotation) { + display_.set_rotation(rotation); + root_window_->SetTransform(GetRotationTransform() * GetUIScaleTransform()); +} + +void TestScreen::SetUIScale(float ui_scale) { + ui_scale_ = ui_scale; + root_window_->SetTransform(GetRotationTransform() * GetUIScaleTransform()); +} + +gfx::Transform TestScreen::GetRotationTransform() const { + gfx::Transform rotate; + float one_pixel = 1.0f / display_.device_scale_factor(); + switch (display_.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; + } + + return rotate; +} + +gfx::Transform TestScreen::GetUIScaleTransform() const { + gfx::Transform ui_scale; + ui_scale.Scale(1.0f / ui_scale_, 1.0f / ui_scale_); + return ui_scale; +} + bool TestScreen::IsDIPEnabled() { return true; } @@ -97,7 +137,9 @@ void TestScreen::AddObserver(gfx::DisplayObserver* observer) { void TestScreen::RemoveObserver(gfx::DisplayObserver* observer) { } -TestScreen::TestScreen(const gfx::Rect& screen_bounds) : root_window_(NULL) { +TestScreen::TestScreen(const gfx::Rect& screen_bounds) + : root_window_(NULL), + ui_scale_(1.0f) { static int64 synthesized_display_id = 2000; display_.set_id(synthesized_display_id++); display_.SetScaleAndBounds(1.0f, screen_bounds); diff --git a/ui/aura/test/test_screen.h b/ui/aura/test/test_screen.h index 1d14cbc..c4615c7 100644 --- a/ui/aura/test/test_screen.h +++ b/ui/aura/test/test_screen.h @@ -12,6 +12,7 @@ namespace gfx { class Rect; +class Transform; } namespace aura { @@ -30,8 +31,13 @@ class TestScreen : public gfx::Screen, RootWindow* CreateRootWindowForPrimaryDisplay(); void SetDeviceScaleFactor(float device_scale_fator); + void SetDisplayRotation(gfx::Display::Rotation rotation); + void SetUIScale(float ui_scale); protected: + gfx::Transform GetRotationTransform() const; + gfx::Transform GetUIScaleTransform() const; + // WindowObserver overrides: virtual void OnWindowBoundsChanged(Window* window, const gfx::Rect& old_bounds, @@ -60,6 +66,8 @@ class TestScreen : public gfx::Screen, gfx::Display display_; + float ui_scale_; + DISALLOW_COPY_AND_ASSIGN(TestScreen); }; diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp index 3e3fbd0..464c43d 100644 --- a/ui/compositor/compositor.gyp +++ b/ui/compositor/compositor.gyp @@ -87,6 +87,8 @@ 'test/compositor_test_support.h', 'test/test_layers.cc', 'test/test_layers.h', + 'test/test_suite.cc', + 'test/test_suite.h', ], 'conditions': [ ['os_posix == 1 and OS != "mac"', { @@ -132,8 +134,6 @@ 'test/test_layer_animation_delegate.h', 'test/test_layer_animation_observer.cc', 'test/test_layer_animation_observer.h', - 'test/test_suite.cc', - 'test/test_suite.h', 'test/test_utils.cc', 'test/test_utils.h', ], diff --git a/ui/snapshot/snapshot.gyp b/ui/snapshot/snapshot.gyp index cf93fa9..6e7eb1a 100644 --- a/ui/snapshot/snapshot.gyp +++ b/ui/snapshot/snapshot.gyp @@ -48,14 +48,24 @@ '../../skia/skia.gyp:skia', '../../base/base.gyp:base', '../../testing/gtest.gyp:gtest', - '../../testing/gmock.gyp:gmock', - '../../testing/gtest.gyp:gtest', '../ui.gyp:ui', 'snapshot' ], 'sources': [ + 'snapshot_aura_unittest.cc', 'snapshot_mac_unittest.mm', - ] + 'test/run_all_unittests.cc', + ], + 'conditions': [ + ['use_aura==1', { + 'dependencies': [ + '../../base/base.gyp:test_support_base', + '../aura/aura.gyp:aura_test_support', + '../compositor/compositor.gyp:compositor', + '../compositor/compositor.gyp:compositor_test_support', + ], + }], + ], }, ], 'conditions': [ diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc index 144ce2d..32b1340 100644 --- a/ui/snapshot/snapshot_aura.cc +++ b/ui/snapshot/snapshot_aura.cc @@ -6,13 +6,20 @@ #include "base/logging.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkPixelRef.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/compositor/compositor.h" #include "ui/compositor/dip_util.h" #include "ui/compositor/layer.h" #include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/display.h" #include "ui/gfx/rect.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/rect_f.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/skbitmap_operations.h" +#include "ui/gfx/transform.h" namespace ui { @@ -27,17 +34,17 @@ bool GrabWindowSnapshot(gfx::NativeWindow window, const gfx::Rect& snapshot_bounds) { ui::Compositor* compositor = window->layer()->GetCompositor(); - gfx::Rect read_pixels_bounds = snapshot_bounds; + gfx::RectF read_pixels_bounds = snapshot_bounds; // We must take into account the window's position on the desktop. - gfx::Point origin = window->bounds().origin(); - const aura::Window* root_window = window->GetRootWindow(); + read_pixels_bounds.Offset( + window->GetBoundsInRootWindow().origin().OffsetFromOrigin()); + aura::RootWindow* root_window = window->GetRootWindow(); if (root_window) - aura::Window::ConvertPointToTarget(window, root_window, &origin); + root_window->GetRootTransform().TransformRect(&read_pixels_bounds); - read_pixels_bounds.Offset(origin.OffsetFromOrigin()); gfx::Rect read_pixels_bounds_in_pixel = - ui::ConvertRectToPixel(window->layer(), read_pixels_bounds); + gfx::ToEnclosingRect(read_pixels_bounds); // Sometimes (i.e. when using Aero on Windows) the compositor's size is // smaller than the window bounds. So trim appropriately. @@ -50,10 +57,29 @@ bool GrabWindowSnapshot(gfx::NativeWindow window, if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel)) return false; - unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels()); + gfx::Display display = + gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window); + switch (display.rotation()) { + case gfx::Display::ROTATE_0: + break; + case gfx::Display::ROTATE_90: + bitmap = SkBitmapOperations::Rotate( + bitmap, SkBitmapOperations::ROTATION_270_CW); + break; + case gfx::Display::ROTATE_180: + bitmap = SkBitmapOperations::Rotate( + bitmap, SkBitmapOperations::ROTATION_180_CW); + break; + case gfx::Display::ROTATE_270: + bitmap = SkBitmapOperations::Rotate( + bitmap, SkBitmapOperations::ROTATION_90_CW); + break; + } + unsigned char* pixels = reinterpret_cast<unsigned char*>( + bitmap.pixelRef()->pixels()); gfx::PNGCodec::Encode(pixels, gfx::PNGCodec::FORMAT_BGRA, - read_pixels_bounds_in_pixel.size(), + gfx::Size(bitmap.width(), bitmap.height()), bitmap.rowBytes(), true, std::vector<gfx::PNGCodec::Comment>(), png_representation); diff --git a/ui/snapshot/snapshot_aura_unittest.cc b/ui/snapshot/snapshot_aura_unittest.cc new file mode 100644 index 0000000..8f93c16 --- /dev/null +++ b/ui/snapshot/snapshot_aura_unittest.cc @@ -0,0 +1,222 @@ +// 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 "ui/snapshot/snapshot.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/aura_test_helper.h" +#include "ui/aura/test/test_screen.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/aura/test/test_windows.h" +#include "ui/aura/window.h" +#include "ui/compositor/compositor_setup.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/gfx_paths.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size_conversions.h" +#include "ui/gfx/transform.h" +#include "ui/gl/gl_implementation.h" + +namespace ui { +namespace { +const SkColor kPaintColor = SK_ColorRED; + +// Paint simple rectangle on the specified aura window. +class TestPaintingWindowDelegate : public aura::test::TestWindowDelegate { + public: + explicit TestPaintingWindowDelegate(const gfx::Size& window_size) + : window_size_(window_size) { + } + + virtual ~TestPaintingWindowDelegate() { + } + + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + canvas->FillRect(gfx::Rect(window_size_), kPaintColor); + } + + private: + gfx::Size window_size_; + + DISALLOW_COPY_AND_ASSIGN(TestPaintingWindowDelegate); +}; + +size_t GetFailedPixelsCount(const gfx::Image& image) { + const SkBitmap* bitmap = image.ToSkBitmap(); + uint32* bitmap_data = reinterpret_cast<uint32*>( + bitmap->pixelRef()->pixels()); + size_t result = 0; + for (int i = 0; i < bitmap->width() * bitmap->height(); ++i) { + if (static_cast<SkColor>(bitmap_data[i]) != kPaintColor) + ++result; + } + return result; +} + +} // namespace + +class SnapshotAuraTest : public testing::Test { + public: + SnapshotAuraTest() {} + virtual ~SnapshotAuraTest() {} + + virtual void SetUp() OVERRIDE { + testing::Test::SetUp(); + helper_.reset(new aura::test::AuraTestHelper(MessageLoopForUI::current())); + helper_->SetUp(); + } + + virtual void TearDown() OVERRIDE { + test_window_.reset(); + delegate_.reset(); + helper_->RunAllPendingInMessageLoop(); + helper_->TearDown(); + testing::Test::TearDown(); + } + + protected: + aura::Window* test_window() { return test_window_.get(); } + aura::RootWindow* root_window() { return helper_->root_window(); } + aura::TestScreen* test_screen() { return helper_->test_screen(); } + + void WaitForDraw() { + root_window()->compositor()->ScheduleDraw(); + ui::DrawWaiterForTest::Wait(root_window()->compositor()); + } + + void SetupTestWindow(const gfx::Rect& window_bounds) { + delegate_.reset(new TestPaintingWindowDelegate(window_bounds.size())); + test_window_.reset(aura::test::CreateTestWindowWithDelegate( + delegate_.get(), 0, window_bounds, root_window())); + } + + gfx::Image GrabSnapshotForTestWindow() { + std::vector<unsigned char> png_representation; + gfx::Rect local_bounds(test_window_->bounds().size()); + ui::GrabWindowSnapshot(test_window(), &png_representation, local_bounds); + return gfx::Image::CreateFrom1xPNGBytes( + &(png_representation[0]), png_representation.size()); + } + + private: + scoped_ptr<aura::test::AuraTestHelper> helper_; + scoped_ptr<aura::Window> test_window_; + scoped_ptr<TestPaintingWindowDelegate> delegate_; + std::vector<unsigned char> png_representation_; + + DISALLOW_COPY_AND_ASSIGN(SnapshotAuraTest); +}; + +TEST_F(SnapshotAuraTest, FullScreenWindow) { + SetupTestWindow(root_window()->bounds()); + WaitForDraw(); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(test_window()->bounds().size().ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, PartialBounds) { + gfx::Rect test_bounds(100, 100, 300, 200); + SetupTestWindow(test_bounds); + WaitForDraw(); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(test_bounds.size().ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, Rotated) { + test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90); + + gfx::Rect test_bounds(100, 100, 300, 200); + SetupTestWindow(test_bounds); + WaitForDraw(); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(test_bounds.size().ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, UIScale) { + const float kUIScale = 1.25f; + test_screen()->SetUIScale(kUIScale); + + gfx::Rect test_bounds(100, 100, 300, 200); + SetupTestWindow(test_bounds); + WaitForDraw(); + + // Snapshot always captures the physical pixels. + gfx::SizeF snapshot_size(test_bounds.size()); + snapshot_size.Scale(1.0f / kUIScale); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, DeviceScaleFactor) { + test_screen()->SetDeviceScaleFactor(2.0f); + + gfx::Rect test_bounds(100, 100, 150, 100); + SetupTestWindow(test_bounds); + WaitForDraw(); + + // Snapshot always captures the physical pixels. + gfx::SizeF snapshot_size(test_bounds.size()); + snapshot_size.Scale(2.0f); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, RotateAndUIScale) { + const float kUIScale = 1.25f; + test_screen()->SetUIScale(kUIScale); + test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90); + + gfx::Rect test_bounds(100, 100, 300, 200); + SetupTestWindow(test_bounds); + WaitForDraw(); + + // Snapshot always captures the physical pixels. + gfx::SizeF snapshot_size(test_bounds.size()); + snapshot_size.Scale(1.0f / kUIScale); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +TEST_F(SnapshotAuraTest, RotateAndUIScaleAndScaleFactor) { + test_screen()->SetDeviceScaleFactor(2.0f); + const float kUIScale = 1.25f; + test_screen()->SetUIScale(kUIScale); + test_screen()->SetDisplayRotation(gfx::Display::ROTATE_90); + + gfx::Rect test_bounds(20, 30, 150, 100); + SetupTestWindow(test_bounds); + WaitForDraw(); + + // Snapshot always captures the physical pixels. + gfx::SizeF snapshot_size(test_bounds.size()); + snapshot_size.Scale(2.0f / kUIScale); + + gfx::Image snapshot = GrabSnapshotForTestWindow(); + EXPECT_EQ(gfx::ToRoundedSize(snapshot_size).ToString(), + snapshot.Size().ToString()); + EXPECT_EQ(0u, GetFailedPixelsCount(snapshot)); +} + +} // namespace ui diff --git a/ui/snapshot/test/run_all_unittests.cc b/ui/snapshot/test/run_all_unittests.cc new file mode 100644 index 0000000..5bf3d5f --- /dev/null +++ b/ui/snapshot/test/run_all_unittests.cc @@ -0,0 +1,14 @@ +// 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 "base/test/test_suite.h" +#include "ui/compositor/test/test_suite.h" + +int main(int argc, char** argv) { +#if defined(USE_AURA) + return ui::test::CompositorTestSuite(argc, argv).Run(); +#else + return base::TestSuite(argc, argv).Run(); +#endif +} |