Add additional tests for the software cursor
Follow-up from https://crrev.com/c/4310794. Test that the software cursor representation, size, hotspot and window are correct. Bug: 1229231 Change-Id: If113795abefd6ccde62946d1b1985eb58a6385ac Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4255949 Reviewed-by: Mitsuru Oshima <oshima@chromium.org> Commit-Queue: Henrique Ferreiro <hferreiro@igalia.com> Cr-Commit-Position: refs/heads/main@{#1119833}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
0bcb7b459b
commit
35f4dce600
@ -485,6 +485,10 @@ void CursorWindowController::UpdateCursorImage() {
|
||||
image =
|
||||
*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
|
||||
}
|
||||
// Use `gfx::ToFlooredPoint` as `ImageSkiaRep::GetWidth` is implemented as
|
||||
// `return static_cast<int>(pixel_width() / scale());`.
|
||||
hot_point_ = gfx::ToFlooredPoint(
|
||||
gfx::ConvertPointToDips(hot_point_in_physical_pixels, cursor_scale));
|
||||
|
||||
gfx::ImageSkia resized = image;
|
||||
|
||||
@ -499,8 +503,7 @@ void CursorWindowController::UpdateCursorImage() {
|
||||
resized = gfx::ImageSkiaOperations::CreateResizedImage(
|
||||
image, skia::ImageOperations::ResizeMethod::RESIZE_BEST,
|
||||
gfx::ScaleToCeiledSize(image.size(), rescale));
|
||||
hot_point_in_physical_pixels =
|
||||
gfx::ScaleToCeiledPoint(hot_point_in_physical_pixels, rescale);
|
||||
hot_point_ = gfx::ScaleToCeiledPoint(hot_point_, rescale);
|
||||
}
|
||||
|
||||
if (cursor_color_ != kDefaultCursorColor) {
|
||||
@ -511,10 +514,6 @@ void CursorWindowController::UpdateCursorImage() {
|
||||
|
||||
delegate_->SetCursorImage(resized.size(), resized);
|
||||
|
||||
// TODO(danakj): Should this be rounded? Or kept as a floating point?
|
||||
hot_point_ = gfx::ToFlooredPoint(
|
||||
gfx::ConvertPointToDips(hot_point_in_physical_pixels, cursor_scale));
|
||||
|
||||
if (cursor_view_widget_) {
|
||||
static_cast<cursor::CursorView*>(cursor_view_widget_->GetContentsView())
|
||||
->SetCursorImage(delegate_->cursor_image(), delegate_->size(),
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "ash/display/cursor_window_controller.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "ash/accessibility/accessibility_controller_impl.h"
|
||||
#include "ash/constants/ash_constants.h"
|
||||
#include "ash/constants/ash_pref_names.h"
|
||||
@ -14,7 +16,9 @@
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/notreached.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "ui/aura/client/cursor_shape_client.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/cursor/cursor.h"
|
||||
@ -22,19 +26,28 @@
|
||||
#include "ui/base/layout.h"
|
||||
#include "ui/base/resource/mock_resource_bundle_delegate.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "ui/base/resource/resource_scale_factor.h"
|
||||
#include "ui/display/display.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/display/test/display_manager_test_api.h"
|
||||
#include "ui/events/test/event_generator.h"
|
||||
#include "ui/gfx/color_utils.h"
|
||||
#include "ui/gfx/geometry/dip_util.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/point_conversions.h"
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
#include "ui/gfx/geometry/size_conversions.h"
|
||||
#include "ui/gfx/geometry/skia_conversions.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/image/image_skia_rep.h"
|
||||
#include "ui/gfx/image/image_skia_source.h"
|
||||
#include "ui/wm/core/coordinate_conversion.h"
|
||||
#include "ui/wm/core/cursor_manager.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
using ::ui::mojom::CursorType;
|
||||
|
||||
class CursorWindowControllerTest : public AshTestBase {
|
||||
public:
|
||||
CursorWindowControllerTest() = default;
|
||||
@ -57,7 +70,7 @@ class CursorWindowControllerTest : public AshTestBase {
|
||||
SetCursorCompositionEnabled(true);
|
||||
}
|
||||
|
||||
ui::mojom::CursorType GetCursorType() const {
|
||||
CursorType GetCursorType() const {
|
||||
return cursor_window_controller_->cursor_.type();
|
||||
}
|
||||
|
||||
@ -116,7 +129,7 @@ TEST_F(CursorWindowControllerTest, MoveToDifferentDisplay) {
|
||||
|
||||
EXPECT_TRUE(primary_root->Contains(GetCursorWindow()));
|
||||
EXPECT_EQ(primary_display_id, GetCursorDisplayId());
|
||||
EXPECT_EQ(ui::mojom::CursorType::kNull, GetCursorType());
|
||||
EXPECT_EQ(CursorType::kNull, GetCursorType());
|
||||
gfx::Point hot_point = GetCursorHotPoint();
|
||||
EXPECT_EQ(gfx::Point(4, 4), hot_point);
|
||||
gfx::Rect cursor_bounds = GetCursorWindow()->GetBoundsInScreen();
|
||||
@ -140,7 +153,7 @@ TEST_F(CursorWindowControllerTest, MoveToDifferentDisplay) {
|
||||
|
||||
EXPECT_TRUE(secondary_root->Contains(GetCursorWindow()));
|
||||
EXPECT_EQ(secondary_display_id, GetCursorDisplayId());
|
||||
EXPECT_EQ(ui::mojom::CursorType::kNull, GetCursorType());
|
||||
EXPECT_EQ(CursorType::kNull, GetCursorType());
|
||||
hot_point = GetCursorHotPoint();
|
||||
EXPECT_EQ(gfx::Point(3, 3), hot_point);
|
||||
cursor_bounds = GetCursorWindow()->GetBoundsInScreen();
|
||||
@ -251,6 +264,92 @@ TEST_F(CursorWindowControllerTest, ScaleUsesCorrectAssets) {
|
||||
ui::ResourceBundle::SwapSharedInstanceForTesting(original);
|
||||
}
|
||||
|
||||
// Test different properties of the composited cursor with different device
|
||||
// scale factors and zoom levels.
|
||||
TEST_F(CursorWindowControllerTest, DSF) {
|
||||
auto* const cursor_shape_client = aura::client::GetCursorShapeClient();
|
||||
DCHECK(cursor_shape_client);
|
||||
|
||||
auto cursor_test = [&](ui::Cursor cursor, float size, float cursor_scale) {
|
||||
const float dsf =
|
||||
display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
|
||||
SCOPED_TRACE(testing::Message() << cursor.type() << " at scale " << dsf
|
||||
<< " and size " << size);
|
||||
|
||||
cursor_window_controller()->SetCursor(cursor);
|
||||
const absl::optional<ui::CursorData> cursor_data =
|
||||
cursor_shape_client->GetCursorData(cursor);
|
||||
DCHECK(cursor_data);
|
||||
|
||||
// Software cursors look blurry if they are resized by the window they are
|
||||
// rendered in, instead of by `ImageSkia`. Make sure
|
||||
// `CursorWindowController` creates the cursor in a way that a
|
||||
// representation for the display's device scale factor can be directly
|
||||
// obtained.
|
||||
const gfx::ImageSkiaRep& rep = GetCursorImage().GetRepresentation(dsf);
|
||||
EXPECT_EQ(rep.scale(), dsf);
|
||||
|
||||
const gfx::Size kOriginalCursorSize =
|
||||
// ImageSkiaRep::GetWidth() uses static_cast<int>.
|
||||
gfx::ToFlooredSize(gfx::ConvertSizeToDips(
|
||||
gfx::SkISizeToSize(cursor_data->bitmaps[0].dimensions()),
|
||||
cursor_scale));
|
||||
const gfx::Size kCursorSize =
|
||||
size != 0 ? gfx::Size(size, size) : kOriginalCursorSize;
|
||||
EXPECT_EQ(GetCursorImage().size(), kCursorSize);
|
||||
|
||||
// TODO(hferreiro): the cursor hotspot for non-custom cursors cannot be
|
||||
// checked, since the software cursor uses `ImageSkia::MapToResourceScale`,
|
||||
// and `CursorLoader::GetCursorData` uses
|
||||
// `ui::GetSupportedResourceScaleFactor`, and 2x cursor hotspots are not
|
||||
// just twice the 1x hotspots.
|
||||
if (cursor.type() == CursorType::kCustom) {
|
||||
const gfx::Point kHotspot = gfx::ToFlooredPoint(
|
||||
gfx::ConvertPointToDips(cursor_data->hotspot, cursor_scale));
|
||||
const float rescale =
|
||||
static_cast<float>(kCursorSize.width()) / kOriginalCursorSize.width();
|
||||
EXPECT_EQ(GetCursorHotPoint(),
|
||||
gfx::ScaleToCeiledPoint(kHotspot, rescale));
|
||||
}
|
||||
|
||||
// The cursor window should have the same size as the cursor.
|
||||
EXPECT_EQ(GetCursorWindow()->bounds().size(), GetCursorImage().size());
|
||||
};
|
||||
|
||||
auto* const cursor_manager = Shell::Get()->cursor_manager();
|
||||
DCHECK(cursor_manager);
|
||||
|
||||
for (const float device_scale_factor : {1.0f, 1.5f, 2.0f, 2.5f}) {
|
||||
for (const float zoom : {0.8f, 1.0f, 1.25f}) {
|
||||
UpdateDisplay(
|
||||
base::StringPrintf("1000x500*%f@%f", device_scale_factor, zoom));
|
||||
const float dsf = display::Screen::GetScreen()
|
||||
->GetPrimaryDisplay()
|
||||
.device_scale_factor();
|
||||
|
||||
for (const int size : {0, 32, 64}) {
|
||||
cursor_manager->SetCursorSize(size == 0 ? ui::CursorSize::kNormal
|
||||
: ui::CursorSize::kLarge);
|
||||
Shell::Get()->SetLargeCursorSizeInDip(size);
|
||||
|
||||
// Default cursor.
|
||||
cursor_test(CursorType::kPointer, size,
|
||||
// Use the nearest resource scale factor.
|
||||
ui::GetScaleForResourceScaleFactor(
|
||||
ui::GetSupportedResourceScaleFactor(dsf)));
|
||||
|
||||
// Custom cursor.
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocN32Pixels(20, 20);
|
||||
// Custom cursors are always scaled at the device scale factor. See
|
||||
// `WebCursor::GetNativeCursor`.
|
||||
cursor_test(ui::Cursor::NewCustom(bitmap, gfx::Point(10, 10), dsf),
|
||||
size, dsf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that cursor compositing is enabled if at least one of the features that
|
||||
// use it is enabled.
|
||||
TEST_F(CursorWindowControllerTest, ShouldEnableCursorCompositing) {
|
||||
@ -282,23 +381,19 @@ TEST_F(CursorWindowControllerTest, CursorColoringSpotCheck) {
|
||||
gfx::NativeCursor cursor;
|
||||
} kTestCases[] = {
|
||||
// Cursors should still have white.
|
||||
{SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorWHITE,
|
||||
ui::mojom::CursorType::kHand},
|
||||
{SK_ColorBLUE, SK_ColorMAGENTA, SK_ColorWHITE,
|
||||
ui::mojom::CursorType::kCell},
|
||||
{SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
|
||||
ui::mojom::CursorType::kNoDrop},
|
||||
{SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorWHITE, CursorType::kHand},
|
||||
{SK_ColorBLUE, SK_ColorMAGENTA, SK_ColorWHITE, CursorType::kCell},
|
||||
{SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, CursorType::kNoDrop},
|
||||
// Also cursors should still have transparent.
|
||||
{SK_ColorRED, SK_ColorGREEN, SK_ColorTRANSPARENT,
|
||||
ui::mojom::CursorType::kPointer},
|
||||
{SK_ColorRED, SK_ColorGREEN, SK_ColorTRANSPARENT, CursorType::kPointer},
|
||||
// The no drop cursor has red in it, check it's still there:
|
||||
// Most of the cursor should be colored, but the red part shouldn't be
|
||||
// re-colored.
|
||||
{SK_ColorBLUE, SK_ColorGREEN, SkColorSetRGB(173, 8, 8),
|
||||
ui::mojom::CursorType::kNoDrop},
|
||||
CursorType::kNoDrop},
|
||||
// Similarly, the copy cursor has green in it.
|
||||
{SK_ColorBLUE, SK_ColorRED, SkColorSetRGB(19, 137, 16),
|
||||
ui::mojom::CursorType::kCopy},
|
||||
CursorType::kCopy},
|
||||
};
|
||||
|
||||
for (const auto& test : kTestCases) {
|
||||
|
Reference in New Issue
Block a user