910e62b5创建于 1月15日历史提交
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/aura/test/test_screen.h"

#include <stdint.h>

#include "base/check_op.h"
#include "base/containers/adapters.h"
#include "build/build_config.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/compositor/compositor.h"
#include "ui/display/display_transform.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/platform_window/platform_window_init_properties.h"

namespace aura {

namespace {

bool IsRotationPortrait(display::Display::Rotation rotation) {
  return rotation == display::Display::ROTATE_90 ||
         rotation == display::Display::ROTATE_270;
}

}  // namespace

// static
TestScreen* TestScreen::Create(const gfx::Size& size) {
  const gfx::Size kDefaultSize(800, 600);
  // Use (0,0) because the desktop aura tests are executed in
  // native environment where the display's origin is (0,0).
  return new TestScreen(gfx::Rect(size.IsEmpty() ? kDefaultSize : size));
}

TestScreen::~TestScreen() {
  delete host_;
}

WindowTreeHost* TestScreen::CreateHostForPrimaryDisplay() {
  DCHECK(!host_);
  ui::PlatformWindowInitProperties properties(
      gfx::Rect(GetPrimaryDisplay().GetSizeInPixel()));
  host_ = WindowTreeHost::Create(std::move(properties)).release();
  // 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);
  // Other test code may have already initialized the compositor.
  if (!host_->compositor()->root_layer())
    host_->InitHost();
  host_->window()->Show();
  return host_;
}

void TestScreen::SetDeviceScaleFactor(float device_scale_factor,
                                      bool resize_host) {
  display::Display display(GetPrimaryDisplay());
  gfx::Rect bounds_in_pixel(display.GetSizeInPixel());
  display.SetScaleAndBounds(device_scale_factor, bounds_in_pixel);
  display_list().UpdateDisplay(display);
  if (resize_host)
    host_->OnHostResizedInPixels(bounds_in_pixel.size());
}

void TestScreen::SetColorSpace(const gfx::ColorSpace& color_space,
                               float sdr_white_level) {
  display::Display display(GetPrimaryDisplay());
  gfx::DisplayColorSpaces display_color_spaces(
      color_space, viz::SinglePlaneFormat::kRGBA_8888);
  display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
  display.SetColorSpaces(display_color_spaces);
  display_list().UpdateDisplay(display);
}

void TestScreen::SetDisplayRotation(display::Display::Rotation rotation) {
  display::Display display(GetPrimaryDisplay());
  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);
  display_list().UpdateDisplay(display);
  host_->SetRootTransform(GetUIScaleTransform() * GetRotationTransform());
}

void TestScreen::SetUIScale(float ui_scale) {
  ui_scale_ = ui_scale;
  display::Display display(GetPrimaryDisplay());
  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);
  display_list().UpdateDisplay(display);
  host_->SetRootTransform(GetUIScaleTransform() * GetRotationTransform());
}

void TestScreen::SetWorkAreaInsets(const gfx::Insets& insets) {
  display::Display display(GetPrimaryDisplay());
  display.UpdateWorkAreaFromInsets(insets);
  display_list().UpdateDisplay(display);
}

void TestScreen::SetPreferredScaleFactorForWindow(gfx::NativeWindow window,
                                                  float scale_factor) {
  preferred_scale_factors_[window] = scale_factor;
}

gfx::Transform TestScreen::GetRotationTransform() const {
  display::Display display = GetPrimaryDisplay();
  return display::CreateRotationTransform(display.rotation(),
                                          gfx::SizeF(display.size()));
}

gfx::Transform TestScreen::GetUIScaleTransform() const {
  gfx::Transform ui_scale;
  ui_scale.Scale(1.0f / ui_scale_, 1.0f / ui_scale_);
  return ui_scale;
}

void TestScreen::OnWindowBoundsChanged(Window* window,
                                       const gfx::Rect& old_bounds,
                                       const gfx::Rect& new_bounds,
                                       ui::PropertyChangeReason reason) {
  DCHECK_EQ(host_->window(), window);
  display::Display display(GetPrimaryDisplay());
  display.SetSize(gfx::ScaleToFlooredSize(new_bounds.size(),
                                          display.device_scale_factor()));
  display_list().UpdateDisplay(display);
}

void TestScreen::OnWindowDestroying(Window* window) {
  if (host_->window() == window) {
    host_->window()->RemoveObserver(this);
    host_ = nullptr;
  }
}

gfx::Point TestScreen::GetCursorScreenPoint() {
  return Env::GetInstance()->last_mouse_location();
}

bool TestScreen::IsWindowUnderCursor(gfx::NativeWindow window) {
  return GetWindowAtScreenPoint(GetCursorScreenPoint()) == window;
}

gfx::NativeWindow TestScreen::GetWindowForPoint(Window* window,
                                                const gfx::Point& local_point) {
  DCHECK(window);
  if (!window->IsVisible()) {
    return nullptr;
  }

  if (!window->HitTest(local_point)) {
    return nullptr;
  }

  for (Window* child : base::Reversed(window->children())) {
    gfx::Point point_in_child_coords(local_point);
    Window::ConvertPointToTarget(window, child, &point_in_child_coords);
    Window* match = GetWindowForPoint(child, point_in_child_coords);
    if (match) {
      return match;
    }
  }
  return window;
}

gfx::NativeWindow TestScreen::GetWindowAtScreenPoint(const gfx::Point& point) {
  if (!host_ || !host_->window())
    return nullptr;

  // GetWindowAtScreenPoint() is designed to return a visible window that
  // contains the given point within its bounds. Using GetEventHandlerForPoint()
  // can lead to null returns for windows that don't have an event handler, such
  // as content_window_ in DesktopNativeWidgetAura.
  return GetWindowForPoint(host_->window(), point);
}

gfx::NativeWindow TestScreen::GetLocalProcessWindowAtPoint(
    const gfx::Point& point,
    const std::set<gfx::NativeWindow>& ignore) {
  return nullptr;
}

display::Display TestScreen::GetDisplayNearestWindow(
    gfx::NativeWindow window) const {
  return GetPrimaryDisplay();
}

std::string TestScreen::GetCurrentWorkspace() {
  return {};
}

std::optional<float> TestScreen::GetPreferredScaleFactorForWindow(
    gfx::NativeWindow window) const {
  if (auto it = preferred_scale_factors_.find(window);
      it != preferred_scale_factors_.end()) {
    return it->second;
  }
  return Screen::GetPreferredScaleFactorForWindow(window);
}

TestScreen::TestScreen(const gfx::Rect& screen_bounds) {
  static int64_t synthesized_display_id = 2000;
  display::Display display(synthesized_display_id++);
  display.SetScaleAndBounds(1.0f, screen_bounds);
  ProcessDisplayChanged(display, true /* is_primary */);
}

}  // namespace aura