| // Copyright 2016 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 "headless/lib/browser/headless_screen.h" |
| |
| #include <stdint.h> |
| |
| #include "base/logging.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/ime/input_method.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/gfx/screen.h" |
| |
| namespace headless { |
| |
| namespace { |
| |
| bool IsRotationPortrait(gfx::Display::Rotation rotation) { |
| return rotation == gfx::Display::ROTATE_90 || |
| rotation == gfx::Display::ROTATE_270; |
| } |
| |
| } // namespace |
| |
| // static |
| HeadlessScreen* HeadlessScreen::Create(const gfx::Size& size) { |
| const gfx::Size kDefaultSize(800, 600); |
| return new HeadlessScreen(gfx::Rect(size.IsEmpty() ? kDefaultSize : size)); |
| } |
| |
| HeadlessScreen::~HeadlessScreen() {} |
| |
| aura::WindowTreeHost* HeadlessScreen::CreateHostForPrimaryDisplay() { |
| DCHECK(!host_); |
| host_ = aura::WindowTreeHost::Create(gfx::Rect(display_.GetSizeInPixel())); |
| // Some tests don't correctly manage window focus/activation states. |
| // Makes sure InputMethod is default focused so that IME basics can work. |
| host_->GetInputMethod()->OnFocus(); |
| host_->window()->AddObserver(this); |
| host_->InitHost(); |
| return host_; |
| } |
| |
| void HeadlessScreen::SetDeviceScaleFactor(float device_scale_factor) { |
| gfx::Rect bounds_in_pixel(display_.GetSizeInPixel()); |
| display_.SetScaleAndBounds(device_scale_factor, bounds_in_pixel); |
| } |
| |
| void HeadlessScreen::SetDisplayRotation(gfx::Display::Rotation rotation) { |
| gfx::Rect bounds_in_pixel(display_.GetSizeInPixel()); |
| gfx::Rect new_bounds(bounds_in_pixel); |
| if (IsRotationPortrait(rotation) != IsRotationPortrait(display_.rotation())) { |
| new_bounds.set_width(bounds_in_pixel.height()); |
| new_bounds.set_height(bounds_in_pixel.width()); |
| } |
| display_.set_rotation(rotation); |
| display_.SetScaleAndBounds(display_.device_scale_factor(), new_bounds); |
| host_->SetRootTransform(GetRotationTransform() * GetUIScaleTransform()); |
| } |
| |
| void HeadlessScreen::SetUIScale(float ui_scale) { |
| ui_scale_ = ui_scale; |
| gfx::Rect bounds_in_pixel(display_.GetSizeInPixel()); |
| gfx::Rect new_bounds = gfx::ToNearestRect( |
| gfx::ScaleRect(gfx::RectF(bounds_in_pixel), 1.0f / ui_scale)); |
| display_.SetScaleAndBounds(display_.device_scale_factor(), new_bounds); |
| host_->SetRootTransform(GetRotationTransform() * GetUIScaleTransform()); |
| } |
| |
| void HeadlessScreen::SetWorkAreaInsets(const gfx::Insets& insets) { |
| display_.UpdateWorkAreaFromInsets(insets); |
| } |
| |
| gfx::Transform HeadlessScreen::GetRotationTransform() const { |
| gfx::Transform rotate; |
| switch (display_.rotation()) { |
| case gfx::Display::ROTATE_0: |
| break; |
| case gfx::Display::ROTATE_90: |
| rotate.Translate(display_.bounds().height(), 0); |
| rotate.Rotate(90); |
| break; |
| case gfx::Display::ROTATE_270: |
| rotate.Translate(0, display_.bounds().width()); |
| rotate.Rotate(270); |
| break; |
| case gfx::Display::ROTATE_180: |
| rotate.Translate(display_.bounds().width(), display_.bounds().height()); |
| rotate.Rotate(180); |
| break; |
| } |
| |
| return rotate; |
| } |
| |
| gfx::Transform HeadlessScreen::GetUIScaleTransform() const { |
| gfx::Transform ui_scale; |
| ui_scale.Scale(1.0f / ui_scale_, 1.0f / ui_scale_); |
| return ui_scale; |
| } |
| |
| void HeadlessScreen::OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) { |
| DCHECK_EQ(host_->window(), window); |
| display_.SetSize(gfx::ScaleToFlooredSize(new_bounds.size(), |
| display_.device_scale_factor())); |
| } |
| |
| void HeadlessScreen::OnWindowDestroying(aura::Window* window) { |
| if (host_->window() == window) |
| host_ = NULL; |
| } |
| |
| gfx::Point HeadlessScreen::GetCursorScreenPoint() { |
| return aura::Env::GetInstance()->last_mouse_location(); |
| } |
| |
| gfx::NativeWindow HeadlessScreen::GetWindowUnderCursor() { |
| return GetWindowAtScreenPoint(GetCursorScreenPoint()); |
| } |
| |
| gfx::NativeWindow HeadlessScreen::GetWindowAtScreenPoint( |
| const gfx::Point& point) { |
| if (!host_ || !host_->window()) |
| return nullptr; |
| return host_->window()->GetTopWindowContainingPoint(point); |
| } |
| |
| int HeadlessScreen::GetNumDisplays() const { |
| return 1; |
| } |
| |
| std::vector<gfx::Display> HeadlessScreen::GetAllDisplays() const { |
| return std::vector<gfx::Display>(1, display_); |
| } |
| |
| gfx::Display HeadlessScreen::GetDisplayNearestWindow( |
| gfx::NativeWindow window) const { |
| return display_; |
| } |
| |
| gfx::Display HeadlessScreen::GetDisplayNearestPoint( |
| const gfx::Point& point) const { |
| return display_; |
| } |
| |
| gfx::Display HeadlessScreen::GetDisplayMatching( |
| const gfx::Rect& match_rect) const { |
| return display_; |
| } |
| |
| gfx::Display HeadlessScreen::GetPrimaryDisplay() const { |
| return display_; |
| } |
| |
| void HeadlessScreen::AddObserver(gfx::DisplayObserver* observer) {} |
| |
| void HeadlessScreen::RemoveObserver(gfx::DisplayObserver* observer) {} |
| |
| HeadlessScreen::HeadlessScreen(const gfx::Rect& screen_bounds) |
| : host_(NULL), ui_scale_(1.0f) { |
| static int64_t synthesized_display_id = 2000; |
| display_.set_id(synthesized_display_id++); |
| display_.SetScaleAndBounds(1.0f, screen_bounds); |
| } |
| |
| } // namespace headless |