chromium/ash/test/pixel/demo_ash_pixel_diff_test.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>

#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/pixel/ash_pixel_differ.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_type.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget.h"

namespace {
constexpr gfx::Size kWidgetSize(50, 50);
}  // namespace

namespace ash {

class DemoAshPixelDiffTest : public AshTestBase {
 public:
  // AshTestBase:
  std::optional<pixel_test::InitParams> CreatePixelTestInitParams()
      const override {
    return pixel_test::InitParams();
  }

  // Creates a top level widget on the display having ID `display_id` with the
  // specified bounds and color.
  std::unique_ptr<views::Widget> CreateWidgetInSolidColor(
      int64_t display_id,
      const gfx::Rect& widget_bounds,
      SkColor color) {
    // Find the root window for the specified display.
    aura::Window* const root_window =
        Shell::Get()->GetRootWindowForDisplayId(display_id);
    CHECK(root_window);

    // Create a top level widget.
    auto widget = std::make_unique<views::Widget>();
    views::Widget::InitParams init_params(
        views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
        views::Widget::InitParams::TYPE_POPUP);
    init_params.bounds = gfx::Rect(widget_bounds);
    init_params.parent = root_window;
    widget->Init(std::move(init_params));
    widget->Show();

    // Set a solid color contents view.
    auto contents_view = std::make_unique<views::View>();
    contents_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
    contents_view->layer()->SetColor(color);
    widget->SetContentsView(std::move(contents_view));

    return widget;
  }

  // Creates top-level widgets at each corner of `display`. Each widget will
  // have size `kWidgetSize` and will be given a unique color. Note that the
  // specified display must be large enough to show all four widgets without
  // any overlap. The returned vector will contain the widgets in the following
  // order: top-left, top-right, bottom-right, bottom-left. .
  std::vector<std::unique_ptr<views::Widget>> CreateWidgetsInCorners(
      const display::Display& display) {
    // `display` should be able to fit all four widgets without overlap.
    const gfx::Rect display_bounds = display.bounds();
    CHECK(display_bounds.width() >= 2 * kWidgetSize.width() &&
          display_bounds.height() >= 2 * kWidgetSize.height());

    // Create the four widgets.
    std::vector<std::unique_ptr<views::Widget>> widgets;

    // Top-left corner.
    const int64_t display_id = display.id();
    widgets.push_back(CreateWidgetInSolidColor(
        display_id, gfx::Rect(kWidgetSize), SK_ColorGRAY));

    // Top-right corner.
    widgets.push_back(CreateWidgetInSolidColor(
        display_id,
        gfx::Rect(gfx::Point(display_bounds.width() - kWidgetSize.width(), 0),
                  kWidgetSize),
        SK_ColorGREEN));

    // Bottom-right corner.
    widgets.push_back(CreateWidgetInSolidColor(
        display_id,
        gfx::Rect(gfx::Point(display_bounds.width() - kWidgetSize.width(),
                             display_bounds.height() - kWidgetSize.height()),
                  kWidgetSize),
        SK_ColorBLUE));

    // Bottom-left corner.
    widgets.push_back(CreateWidgetInSolidColor(
        display_id,
        gfx::Rect(gfx::Point(0, display_bounds.height() - kWidgetSize.height()),
                  kWidgetSize),
        SK_ColorYELLOW));

    return widgets;
  }
};

// Create top level widgets at corners of the primary display. Check the
// screenshot on these widgets.
TEST_F(DemoAshPixelDiffTest, VerifyTopLevelWidgets) {
  // The primary display that is created by default is 800x600 pixels and has a
  // DSF of 1.

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetPrimaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "check_widgets",
      /*revision_number=*/2, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

// Create top level widgets at corners of the primary display, where the primary
// display has non-default device scale factor (DSF). Check the screenshot on
// these widgets.
TEST_F(DemoAshPixelDiffTest, VerifyTopLevelWidgetsForNonDefaultDSF) {
  // Create the display.
  UpdateDisplay("800x600*2");

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetPrimaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "check_widgets",
      /*revision_number=*/0, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

// Create top level widgets at corners of the primary display, for the case
// where there are two displays and the secondary display has a non-default DSF.
// Check the screenshot on these widgets.
TEST_F(DemoAshPixelDiffTest,
       VerifyTopLevelWidgetsOnPrimaryDisplay_SecondaryDisplayHasNonDefaultDSF) {
  // Create the display.
  UpdateDisplay("800x600*1,800x600*2");

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetPrimaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
      "check_widgets",
      /*revision_number=*/0, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

// Create top level widgets at corners of secondary display. Check the
// screenshot on these widgets.
TEST_F(DemoAshPixelDiffTest, VerifyTopLevelWidgetsOnSecondaryDisplay) {
  // Create the displays.
  UpdateDisplay("800x600*1,800x600*1");

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetSecondaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnSecondaryScreen(
      "check_widgets",
      /*revision_number=*/0, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

// Create top level widgets at corners of secondary display, where the secondary
// display has a non-default device scale factor (DSF). Check the screenshot on
// these widgets.
TEST_F(
    DemoAshPixelDiffTest,
    VerifyTopLevelWidgetsOnSecondaryDisplay_SecondaryDisplayHasNonDefaultDSF) {
  // Create the displays.
  UpdateDisplay("800x600*1,800x600*2");

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetSecondaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnSecondaryScreen(
      "check_widgets",
      /*revision_number=*/0, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

// Create top level widgets at corners of secondary display, where both the
// primary and secondary displays have non-default device scale factors (DSFs).
// Check the screenshot on these widgets.
TEST_F(DemoAshPixelDiffTest,
       VerifyTopLevelWidgetsOnSecondaryDisplay_BothDisplaysHaveNonDefaultDSF) {
  // Create the displays.
  UpdateDisplay("800x600*2,800x600*2");

  // Create the widgets.
  const auto widgets = CreateWidgetsInCorners(GetSecondaryDisplay());

  // Verify the UI.
  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnSecondaryScreen(
      "check_widgets",
      /*revision_number=*/0, widgets[0].get(), widgets[1].get(),
      widgets[2].get(), widgets[3].get()));
}

}  // namespace ash