chromium/ash/wm/raster_scale/raster_scale_controller_unittest.cc

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

#include "ash/wm/raster_scale/raster_scale_controller.h"

#include <vector>

#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/raster_scale_change_tracker.h"
#include "base/memory/raw_ptr.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/test/test_windows.h"

namespace ash {

using RasterScaleControllerTest = AshTestBase;

TEST_F(RasterScaleControllerTest, RasterScaleOnlyUpdatesIfChanges) {
  std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(100, 100)));
  auto tracker = RasterScaleChangeTracker(window.get());

  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  {
    ScopedSetRasterScale scoped1(window.get(), 2.0f);
    EXPECT_EQ(2.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{2.0f}, tracker.TakeRasterScaleChanges());

    {
      ScopedSetRasterScale scoped2(window.get(), 2.0f);

      // The raster scale didn't change, so expect no raster scale changes to be
      // sent.
      EXPECT_EQ(2.0f, window->GetProperty(aura::client::kRasterScale));
      EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());
    }

    // Removing the same scale (2.0f) once should still leave the existing 2.0f
    // there.
    EXPECT_EQ(2.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());
  }
  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{1.0f}, tracker.TakeRasterScaleChanges());
}

TEST_F(RasterScaleControllerTest, RasterScalePause) {
  std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(100, 100)));
  auto tracker = RasterScaleChangeTracker(window.get());

  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  auto scoped_pause = std::make_unique<ScopedPauseRasterScaleUpdates>();

  {
    ScopedSetRasterScale scoped1(window.get(), 2.0f);

    // Since updates are paused, expect nothing to change.
    EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

    // Unpausing should set it to 2.0f now.
    scoped_pause.reset();
    EXPECT_EQ(2.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{2.0f}, tracker.TakeRasterScaleChanges());

    // Pause again, and then destroy scoped1.
    scoped_pause = std::make_unique<ScopedPauseRasterScaleUpdates>();
  }

  // It should still be at 2.0f since we are paused.
  EXPECT_EQ(2.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  // Unpausing should set it to 1.0f now.
  scoped_pause.reset();
  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{1.0f}, tracker.TakeRasterScaleChanges());
}

// Tests that raster scale is only updated when it changes by a slop proportion.
TEST_F(RasterScaleControllerTest, RasterScaleSlop) {
  std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(100, 100)));
  auto tracker = RasterScaleChangeTracker(window.get());

  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  const auto slop =
      Shell::Get()->raster_scale_controller()->raster_scale_slop_proportion();

  {
    const auto target_scale = 1.0f + slop * 2.0f;
    ScopedSetRasterScale scoped1(window.get(), target_scale);

    // A 100% change should trigger a change.
    EXPECT_EQ(target_scale, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{target_scale},
              tracker.TakeRasterScaleChanges());
  }

  // Should go back to 1.0f.
  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{1.0f}, tracker.TakeRasterScaleChanges());

  {
    const auto target_scale = 1.0f + slop / 2.0f;
    ScopedSetRasterScale scoped1(window.get(), target_scale);

    // A change of lower proportion than `slop` should not trigger
    // a change.
    EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());
  }

  // Expect no changes after scope ends.
  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  const auto target_scale_h2 = 1.0f + slop / 2.0f;
  {
    ScopedSetRasterScale scoped1(window.get(), target_scale_h2);

    // A change of lower proportion than `slop` should not trigger
    // a change.
    EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

    {
      const auto target_scale_x2 = 1.0f + slop * 2.0f;
      ScopedSetRasterScale scoped2(window.get(), target_scale_x2);

      // Should update to `target_scale_x2`.
      EXPECT_EQ(target_scale_x2,
                window->GetProperty(aura::client::kRasterScale));
      EXPECT_EQ(std::vector<float>{target_scale_x2},
                tracker.TakeRasterScaleChanges());
    }

    // After releasing `scoped2`, the change from `target_scale_x2` to
    // `target_scale_h2` should exceed the raster slop, so expect an update.
    EXPECT_EQ(target_scale_h2, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{target_scale_h2},
              tracker.TakeRasterScaleChanges());
  }

  // Even though the change from `target_scale_h2` to 1.0f should be less
  // than the raster scale slop by proportion, this should be special cased to
  // return it to 1.0f. See comments on `slop`.
  EXPECT_LE((target_scale_h2 - 1.0f) / target_scale_h2, slop);
  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{1.0f}, tracker.TakeRasterScaleChanges());
}

// Tests that raster scale is not reduced below `kMinimumRasterScale`.
TEST_F(RasterScaleControllerTest, RasterScaleMinimumValue) {
  std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(100, 100)));
  auto tracker = RasterScaleChangeTracker(window.get());

  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{}, tracker.TakeRasterScaleChanges());

  {
    // Expect to be able to set raster scale down to the minimum value.
    const auto target_scale = RasterScaleController::kMinimumRasterScale;
    ScopedSetRasterScale scoped1(window.get(), target_scale);
    EXPECT_EQ(target_scale, window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{target_scale},
              tracker.TakeRasterScaleChanges());
  }

  EXPECT_EQ(1.0f, window->GetProperty(aura::client::kRasterScale));
  EXPECT_EQ(std::vector<float>{1.0f}, tracker.TakeRasterScaleChanges());

  {
    // Expect raster scale to not be able to be set below the minimum value.
    const auto target_scale = RasterScaleController::kMinimumRasterScale * 0.9f;
    ScopedSetRasterScale scoped1(window.get(), target_scale);
    EXPECT_EQ(RasterScaleController::kMinimumRasterScale,
              window->GetProperty(aura::client::kRasterScale));
    EXPECT_EQ(std::vector<float>{RasterScaleController::kMinimumRasterScale},
              tracker.TakeRasterScaleChanges());
  }
}

}  // namespace ash