cursor: Use hardware compositing for large cursor whenever possible
(1) When large cursor is enabled, use hardware compositing for cursor if the plane is larger than the large cursor size, otherwise fallback to software compositing. This won't affect other prefs e.g. kAccessibilityHighContrastEnabled or kDockedMagnifierEnabled. Tested with external displays and tested on rotation and magnifier. BUG=308490022 Change-Id: Ibaa7e927652e92ff3a379cb7dedc4b584d649d72 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6222804 Commit-Queue: Yichen Zhou <yichenz@chromium.org> Reviewed-by: Mitsuru Oshima <oshima@chromium.org> Reviewed-by: Reilly Grant <reillyg@chromium.org> Reviewed-by: Xiyuan Xia <xiyuan@chromium.org> Reviewed-by: Mike Wasserman <msw@chromium.org> Cr-Commit-Position: refs/heads/main@{#1417001}
This commit is contained in:
ash
extensions/shell/browser
ui
aura
base
cursor
views
widget
webui
examples
browser
ui
aura
wm
@ -274,8 +274,19 @@ bool CursorWindowController::ShouldEnableCursorCompositing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
return prefs->GetBoolean(prefs::kAccessibilityLargeCursorEnabled) ||
|
||||
prefs->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
|
||||
if (prefs->GetBoolean(prefs::kAccessibilityLargeCursorEnabled)) {
|
||||
// If current display's cursor plane size (i.e. maximum cursor size) is
|
||||
// larger than the large cursor size, then large cursor can be drawn
|
||||
// using hardware plane. Otherwise, software compositing is needed
|
||||
// for cursor.
|
||||
if (gfx::ConvertSizeToDips(display_.maximum_cursor_size(),
|
||||
display_.device_scale_factor())
|
||||
.height() < large_cursor_size_in_dip_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return prefs->GetBoolean(prefs::kAccessibilityHighContrastEnabled) ||
|
||||
prefs->GetBoolean(prefs::kDockedMagnifierEnabled);
|
||||
}
|
||||
|
||||
@ -307,9 +318,6 @@ void CursorWindowController::UpdateContainer() {
|
||||
}
|
||||
|
||||
void CursorWindowController::SetDisplay(const display::Display& display) {
|
||||
if (!is_cursor_compositing_enabled_)
|
||||
return;
|
||||
|
||||
// TODO(oshima): Do not update the composition cursor when crossing
|
||||
// display in unified desktop mode for now. crbug.com/517222.
|
||||
if (Shell::Get()->display_manager()->IsInUnifiedMode() &&
|
||||
@ -322,6 +330,10 @@ void CursorWindowController::SetDisplay(const display::Display& display) {
|
||||
if (!root_window)
|
||||
return;
|
||||
|
||||
if (!is_cursor_compositing_enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetContainer(RootWindowController::ForWindow(root_window)
|
||||
->GetContainer(kShellWindowId_MouseCursorContainer));
|
||||
SetBoundsInScreenAndRotation(display.bounds(), display.rotation());
|
||||
|
@ -290,11 +290,12 @@ TEST_F(CursorWindowControllerTest, ScaleUsesCorrectAssets) {
|
||||
TEST_F(CursorWindowControllerTest, DSF) {
|
||||
const auto& cursor_shape_client = aura::client::GetCursorShapeClient();
|
||||
|
||||
auto cursor_test = [&](ui::Cursor cursor, float size, float cursor_scale) {
|
||||
auto cursor_test = [&](ui::Cursor cursor, float large_cursor_size_in_dip) {
|
||||
const float dsf =
|
||||
display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
|
||||
SCOPED_TRACE(testing::Message() << cursor.type() << " at scale " << dsf
|
||||
<< " and size " << size);
|
||||
SCOPED_TRACE(testing::Message()
|
||||
<< cursor.type() << " at scale " << dsf << " and size "
|
||||
<< large_cursor_size_in_dip);
|
||||
|
||||
cursor_window_controller()->SetCursor(cursor);
|
||||
const std::optional<ui::CursorData> cursor_data =
|
||||
@ -309,16 +310,18 @@ TEST_F(CursorWindowControllerTest, DSF) {
|
||||
const gfx::ImageSkiaRep& rep = GetCursorImage().GetRepresentation(dsf);
|
||||
EXPECT_EQ(rep.scale(), dsf);
|
||||
|
||||
const gfx::Size kOriginalCursorSize =
|
||||
const gfx::Size original_cursor_size_in_dip =
|
||||
// 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;
|
||||
cursor_data->scale_factor));
|
||||
const gfx::Size cursor_size_in_dip =
|
||||
large_cursor_size_in_dip != 0
|
||||
? gfx::Size(large_cursor_size_in_dip, large_cursor_size_in_dip)
|
||||
: original_cursor_size_in_dip;
|
||||
// Scaling operations and conversions between dp and px can cause rounding
|
||||
// errors. We accept rounding errors <= sqrt(1+1).
|
||||
EXPECT_LE(DistanceBetweenSizes(GetCursorImage().size(), kCursorSize),
|
||||
EXPECT_LE(DistanceBetweenSizes(GetCursorImage().size(), cursor_size_in_dip),
|
||||
sqrt(2));
|
||||
|
||||
// TODO(hferreiro): the cursor hotspot for non-custom cursors cannot be
|
||||
@ -327,16 +330,17 @@ TEST_F(CursorWindowControllerTest, DSF) {
|
||||
// `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();
|
||||
const gfx::Point hotspot_in_dip =
|
||||
gfx::ToFlooredPoint(gfx::ConvertPointToDips(
|
||||
cursor_data->hotspot, cursor_data->scale_factor));
|
||||
const float rescale = static_cast<float>(cursor_size_in_dip.height()) /
|
||||
original_cursor_size_in_dip.height();
|
||||
// Scaling operations and conversions between dp and px can cause rounding
|
||||
// errors. We accept rounding errors <= sqrt(1+1).
|
||||
EXPECT_LE(
|
||||
DistanceBetweenPoints(GetCursorHotPoint(),
|
||||
gfx::ScaleToCeiledPoint(kHotspot, rescale)),
|
||||
sqrt(2));
|
||||
ASSERT_LE(DistanceBetweenPoints(
|
||||
GetCursorHotPoint(),
|
||||
gfx::ScaleToCeiledPoint(hotspot_in_dip, rescale)),
|
||||
sqrt(2));
|
||||
}
|
||||
|
||||
// The cursor window should have the same size as the cursor.
|
||||
@ -354,22 +358,20 @@ TEST_F(CursorWindowControllerTest, DSF) {
|
||||
->GetPrimaryDisplay()
|
||||
.device_scale_factor();
|
||||
|
||||
for (const int size : {0, 32, 64, 128}) {
|
||||
cursor_manager->SetCursorSize(size == 0 ? ui::CursorSize::kNormal
|
||||
: ui::CursorSize::kLarge);
|
||||
Shell::Get()->SetLargeCursorSizeInDip(size);
|
||||
for (const int large_cursor_size_in_dip : {0, 32, 64, 128}) {
|
||||
cursor_manager->SetCursorSize(large_cursor_size_in_dip == 0
|
||||
? ui::CursorSize::kNormal
|
||||
: ui::CursorSize::kLarge);
|
||||
Shell::Get()->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
|
||||
// Default cursor.
|
||||
cursor_test(CursorType::kPointer, size,
|
||||
// Use the nearest resource scale factor.
|
||||
ui::GetScaleForResourceScaleFactor(
|
||||
ui::GetSupportedResourceScaleFactor(dsf)));
|
||||
cursor_test(CursorType::kPointer, large_cursor_size_in_dip);
|
||||
|
||||
// Custom cursor. Custom cursors are always scaled at the device scale
|
||||
// factor. See `WebCursor::GetNativeCursor`.
|
||||
cursor_test(ui::Cursor::NewCustom(gfx::test::CreateBitmap(/*size=*/20),
|
||||
gfx::Point(10, 10), dsf),
|
||||
size, dsf);
|
||||
large_cursor_size_in_dip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,18 +382,54 @@ TEST_F(CursorWindowControllerTest, DSF) {
|
||||
TEST_F(CursorWindowControllerTest, ShouldEnableCursorCompositing) {
|
||||
PrefService* prefs =
|
||||
Shell::Get()->session_controller()->GetActivePrefService();
|
||||
display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
|
||||
const float dsf = 2.0f;
|
||||
display.set_device_scale_factor(dsf);
|
||||
display.set_maximum_cursor_size(gfx::Size(128, 128));
|
||||
const gfx::SizeF display_maximum_cursor_size_in_dip =
|
||||
gfx::ConvertSizeToDips(display.maximum_cursor_size(), dsf);
|
||||
|
||||
// Cursor compositing is disabled by default.
|
||||
SetCursorCompositionEnabled(false);
|
||||
EXPECT_FALSE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Enable large cursor, cursor compositing should be enabled.
|
||||
// Enable high contrast feature, cursor compositing should be enabled.
|
||||
prefs->SetBoolean(prefs::kAccessibilityHighContrastEnabled, true);
|
||||
EXPECT_TRUE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Disable high contrast feature, cursor compositing should be disabled.
|
||||
prefs->SetBoolean(prefs::kAccessibilityHighContrastEnabled, false);
|
||||
EXPECT_FALSE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Enable docked magnifier feature, cursor compositing should be enabled.
|
||||
prefs->SetBoolean(prefs::kDockedMagnifierEnabled, true);
|
||||
EXPECT_TRUE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Disable docked magnifier feature, cursor compositing should be disabled.
|
||||
prefs->SetBoolean(prefs::kDockedMagnifierEnabled, false);
|
||||
EXPECT_FALSE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Enable large cursor, cursor compositing should be enabled only if
|
||||
// the target large cursor size is larger than current display's maximum
|
||||
// cursor size.
|
||||
cursor_window_controller()->SetDisplay(display);
|
||||
cursor_window_controller()->SetLargeCursorSizeInDip(
|
||||
display_maximum_cursor_size_in_dip.height() + 1);
|
||||
prefs->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, true);
|
||||
EXPECT_TRUE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Disable large cursor, cursor compositing should be disabled.
|
||||
prefs->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, false);
|
||||
EXPECT_FALSE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
|
||||
// Re-enable large cursor, since large cursor size is smaller than display's
|
||||
// maximum cursor size, cursor should use hardware compositing instead of
|
||||
// software compositing.
|
||||
cursor_window_controller()->SetDisplay(display);
|
||||
cursor_window_controller()->SetLargeCursorSizeInDip(
|
||||
display_maximum_cursor_size_in_dip.height() - 1);
|
||||
prefs->SetBoolean(prefs::kAccessibilityLargeCursorEnabled, true);
|
||||
EXPECT_FALSE(cursor_window_controller()->is_cursor_compositing_enabled());
|
||||
}
|
||||
|
||||
// Test that cursor color works correctly when large cursor is enabled.
|
||||
|
12
ash/shell.cc
12
ash/shell.cc
@ -568,8 +568,7 @@ bool Shell::HasPrimaryStatusArea() {
|
||||
}
|
||||
|
||||
void Shell::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {
|
||||
window_tree_host_manager_->cursor_window_controller()
|
||||
->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
cursor_manager_->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
}
|
||||
|
||||
void Shell::SetCursorColor(SkColor cursor_color) {
|
||||
@ -1497,9 +1496,6 @@ void Shell::Init(
|
||||
resolution_notification_controller_ =
|
||||
std::make_unique<ResolutionNotificationController>();
|
||||
|
||||
cursor_manager_->SetDisplay(
|
||||
display::Screen::GetScreen()->GetPrimaryDisplay());
|
||||
|
||||
// Initialize before AcceleratorController and AshAcceleratorConfiguration.
|
||||
accelerator_prefs_ = std::make_unique<AcceleratorPrefs>(
|
||||
shell_delegate_->CreateAcceleratorPrefsDelegate());
|
||||
@ -1746,6 +1742,12 @@ void Shell::Init(
|
||||
|
||||
window_tree_host_manager_->InitHosts();
|
||||
display_manager_->NotifyDisplaysInitialized();
|
||||
// Set display after `WindowTreeHostManager::InitHosts()`
|
||||
// since root window controller is created in
|
||||
// `WindowTreeHostManager::InitHosts()` and
|
||||
// `CursorWindowManager::SetDisplay` depends on it.
|
||||
cursor_manager_->SetDisplay(
|
||||
display::Screen::GetScreen()->GetPrimaryDisplay());
|
||||
|
||||
if (ash::features::IsBootAnimationEnabled()) {
|
||||
booting_animation_controller_ =
|
||||
|
@ -1341,7 +1341,7 @@ TEST_F(NightLightCrtcTest, TestAllDisplaysSupportCrtcMatrix) {
|
||||
// Test the cursor compositing behavior when Night Light is on (and doesn't
|
||||
// require the software cursor) while other accessibility settings that affect
|
||||
// the cursor are toggled.
|
||||
for (const auto* const pref : {prefs::kAccessibilityLargeCursorEnabled,
|
||||
for (const auto* const pref : {prefs::kDockedMagnifierEnabled,
|
||||
prefs::kAccessibilityHighContrastEnabled}) {
|
||||
user1_pref_service()->SetBoolean(pref, true);
|
||||
EXPECT_TRUE(IsCursorCompositingEnabled());
|
||||
|
@ -121,6 +121,22 @@ void NativeCursorManagerAsh::SetCursorSize(
|
||||
->SetCursorSize(cursor_size);
|
||||
}
|
||||
|
||||
void NativeCursorManagerAsh::SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
::wm::NativeCursorManagerDelegate* delegate) {
|
||||
cursor_loader_.SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
delegate->CommitLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
|
||||
// Sets the cursor to reflect the large cursor size change immediately.
|
||||
if (delegate->IsCursorVisible()) {
|
||||
SetCursor(delegate->GetCursor(), delegate);
|
||||
}
|
||||
|
||||
Shell::Get()
|
||||
->window_tree_host_manager()
|
||||
->cursor_window_controller()
|
||||
->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
}
|
||||
void NativeCursorManagerAsh::SetVisibility(
|
||||
bool visible,
|
||||
::wm::NativeCursorManagerDelegate* delegate) {
|
||||
|
@ -40,6 +40,9 @@ class ASH_EXPORT NativeCursorManagerAsh : public ::wm::NativeCursorManager {
|
||||
::wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetCursor(gfx::NativeCursor cursor,
|
||||
::wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
::wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetVisibility(bool visible,
|
||||
::wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetCursorSize(ui::CursorSize cursor_size,
|
||||
|
@ -121,6 +121,29 @@ TEST_F(NativeCursorManagerAshTest, SetCursorColor) {
|
||||
EXPECT_EQ(ui::kDefaultCursorColor, cursor_manager->GetCursorColor());
|
||||
}
|
||||
|
||||
TEST_F(NativeCursorManagerAshTest, SetLargeCursorSizeInDip) {
|
||||
::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
|
||||
|
||||
EXPECT_EQ(ui::kDefaultLargeCursorSize,
|
||||
cursor_manager->GetLargeCursorSizeInDip());
|
||||
|
||||
cursor_manager->SetLargeCursorSizeInDip(ui::kMaxLargeCursorSize);
|
||||
EXPECT_EQ(ui::kMaxLargeCursorSize, cursor_manager->GetLargeCursorSizeInDip());
|
||||
|
||||
cursor_manager->SetLargeCursorSizeInDip(ui::kMaxLargeCursorSize + 1);
|
||||
EXPECT_EQ(ui::kMaxLargeCursorSize, cursor_manager->GetLargeCursorSizeInDip());
|
||||
|
||||
cursor_manager->SetLargeCursorSizeInDip(ui::kMinLargeCursorSize);
|
||||
EXPECT_EQ(ui::kMinLargeCursorSize, cursor_manager->GetLargeCursorSizeInDip());
|
||||
|
||||
cursor_manager->SetLargeCursorSizeInDip(ui::kMinLargeCursorSize - 1);
|
||||
EXPECT_EQ(ui::kMinLargeCursorSize, cursor_manager->GetLargeCursorSizeInDip());
|
||||
|
||||
cursor_manager->SetLargeCursorSizeInDip(ui::kDefaultLargeCursorSize);
|
||||
EXPECT_EQ(ui::kDefaultLargeCursorSize,
|
||||
cursor_manager->GetLargeCursorSizeInDip());
|
||||
}
|
||||
|
||||
TEST_F(NativeCursorManagerAshTest, SetDeviceScaleFactorAndRotation) {
|
||||
::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
|
||||
const auto& cursor_shape_client = aura::client::GetCursorShapeClient();
|
||||
|
@ -113,6 +113,16 @@ class ShellNativeCursorManager : public wm::NativeCursorManager {
|
||||
SetCursor(delegate->GetCursor(), delegate);
|
||||
}
|
||||
|
||||
void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
::wm::NativeCursorManagerDelegate* delegate) override {
|
||||
cursor_loader_.SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
delegate->CommitLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
if (delegate->IsCursorVisible()) {
|
||||
SetCursor(delegate->GetCursor(), delegate);
|
||||
}
|
||||
}
|
||||
|
||||
void SetMouseEventsEnabled(
|
||||
bool enabled,
|
||||
wm::NativeCursorManagerDelegate* delegate) override {
|
||||
|
@ -56,6 +56,12 @@ class AURA_EXPORT CursorClient {
|
||||
// Gets the type of the mouse cursor icon.
|
||||
virtual ui::CursorSize GetCursorSize() const = 0;
|
||||
|
||||
// Sets the large cursor size in dip.
|
||||
virtual void SetLargeCursorSizeInDip(int large_cursor_size_in_dip) = 0;
|
||||
|
||||
// Gets the large curssor size in dip.
|
||||
virtual int GetLargeCursorSizeInDip() const = 0;
|
||||
|
||||
// Sets the color of the cursor.
|
||||
virtual void SetCursorColor(SkColor color) = 0;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "ui/aura/test/test_cursor_client.h"
|
||||
|
||||
#include "ui/aura/client/cursor_client_observer.h"
|
||||
#include "ui/base/cursor/cursor.h"
|
||||
#include "ui/base/cursor/cursor_size.h"
|
||||
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
|
||||
#include "ui/display/display.h"
|
||||
@ -56,6 +57,12 @@ ui::CursorSize TestCursorClient::GetCursorSize() const {
|
||||
return ui::CursorSize::kNormal;
|
||||
}
|
||||
|
||||
void TestCursorClient::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {}
|
||||
|
||||
int TestCursorClient::GetLargeCursorSizeInDip() const {
|
||||
return ui::kDefaultLargeCursorSize;
|
||||
}
|
||||
|
||||
void TestCursorClient::SetCursorColor(SkColor color) {}
|
||||
|
||||
SkColor TestCursorClient::GetCursorColor() const {
|
||||
|
@ -44,6 +44,8 @@ class TestCursorClient : public aura::client::CursorClient {
|
||||
void HideCursor() override;
|
||||
void SetCursorSize(ui::CursorSize cursor_size) override;
|
||||
ui::CursorSize GetCursorSize() const override;
|
||||
void SetLargeCursorSizeInDip(int large_cursor_size_in_dip) override;
|
||||
int GetLargeCursorSizeInDip() const override;
|
||||
void SetCursorColor(SkColor color) override;
|
||||
SkColor GetCursorColor() const override;
|
||||
bool IsCursorVisible() const override;
|
||||
|
@ -23,6 +23,10 @@ namespace ui {
|
||||
|
||||
inline constexpr SkColor kDefaultCursorColor = SK_ColorBLACK;
|
||||
|
||||
inline constexpr int kDefaultLargeCursorSize = 64;
|
||||
inline constexpr int kMinLargeCursorSize = 25;
|
||||
inline constexpr int kMaxLargeCursorSize = 128;
|
||||
|
||||
struct COMPONENT_EXPORT(UI_BASE_CURSOR) CursorData {
|
||||
public:
|
||||
CursorData();
|
||||
|
@ -79,6 +79,12 @@ void DesktopNativeCursorManager::SetCursorSize(
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void DesktopNativeCursorManager::SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
wm::NativeCursorManagerDelegate* delegate) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void DesktopNativeCursorManager::SetMouseEventsEnabled(
|
||||
bool enabled,
|
||||
wm::NativeCursorManagerDelegate* delegate) {
|
||||
|
@ -56,6 +56,9 @@ class VIEWS_EXPORT DesktopNativeCursorManager : public wm::NativeCursorManager {
|
||||
wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetCursorSize(ui::CursorSize cursor_size,
|
||||
wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
wm::NativeCursorManagerDelegate* delegate) override;
|
||||
void SetMouseEventsEnabled(
|
||||
bool enabled,
|
||||
wm::NativeCursorManagerDelegate* delegate) override;
|
||||
|
@ -94,6 +94,12 @@ class AuraContext::NativeCursorManager : public wm::NativeCursorManager {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
wm::NativeCursorManagerDelegate* delegate) override {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void SetMouseEventsEnabled(
|
||||
bool enabled,
|
||||
wm::NativeCursorManagerDelegate* delegate) override {
|
||||
|
@ -19,7 +19,9 @@
|
||||
#include "ui/base/cursor/mojom/cursor_type.mojom.h"
|
||||
#include "ui/base/cursor/platform_cursor.h"
|
||||
#include "ui/base/resource/resource_scale_factor.h"
|
||||
#include "ui/display/display.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/geometry/skia_conversions.h"
|
||||
#include "ui/wm/core/cursor_util.h"
|
||||
|
||||
namespace wm {
|
||||
@ -30,6 +32,11 @@ using ::ui::mojom::CursorType;
|
||||
|
||||
constexpr base::TimeDelta kAnimatedCursorFrameDelay = base::Milliseconds(25);
|
||||
|
||||
// Converts DIPs (Device-independent pixels) to pixels.
|
||||
int ConvertDipToPixel(int dip, float scale) {
|
||||
return dip * scale;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CursorLoader::CursorLoader(bool use_platform_cursors)
|
||||
@ -46,10 +53,6 @@ void CursorLoader::OnThemeLoaded() {
|
||||
UnloadCursors();
|
||||
}
|
||||
|
||||
void CursorLoader::UnloadCursors() {
|
||||
image_cursors_.clear();
|
||||
}
|
||||
|
||||
bool CursorLoader::SetDisplay(const display::Display& display) {
|
||||
const display::Display::Rotation rotation = display.panel_rotation();
|
||||
const float scale = display.device_scale_factor();
|
||||
@ -74,6 +77,15 @@ void CursorLoader::SetSize(ui::CursorSize size) {
|
||||
UnloadCursors();
|
||||
}
|
||||
|
||||
void CursorLoader::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {
|
||||
if (large_cursor_size_in_dip_ == large_cursor_size_in_dip) {
|
||||
return;
|
||||
}
|
||||
|
||||
large_cursor_size_in_dip_ = large_cursor_size_in_dip;
|
||||
UnloadCursors();
|
||||
}
|
||||
|
||||
void CursorLoader::SetColor(SkColor color) {
|
||||
if (color_ == color) {
|
||||
return;
|
||||
@ -101,38 +113,69 @@ std::optional<ui::CursorData> CursorLoader::GetCursorData(
|
||||
return ui::CursorData();
|
||||
|
||||
if (type == CursorType::kCustom) {
|
||||
SkBitmap custom_bitmap =
|
||||
color_ == ui::kDefaultCursorColor
|
||||
? cursor.custom_bitmap()
|
||||
: wm::GetColorAdjustedBitmap(cursor.custom_bitmap(), color_);
|
||||
return ui::CursorData({custom_bitmap}, cursor.custom_hotspot(),
|
||||
cursor.image_scale_factor());
|
||||
auto cursor_data =
|
||||
ui::CursorData({cursor.custom_bitmap()}, cursor.custom_hotspot(),
|
||||
cursor.image_scale_factor());
|
||||
ApplyColorAndLargeSize(cursor_data);
|
||||
return cursor_data;
|
||||
}
|
||||
|
||||
if (use_platform_cursors_) {
|
||||
// TODO(crbug.com/40175364): consider either passing `scale_` to
|
||||
// `CursorFactory::GetCursorData`, or relying on having called
|
||||
// `CursorFactory::SetDeviceScaleFactor`, instead of appending it here.
|
||||
auto cursor_data = factory_->GetCursorData(type);
|
||||
if (cursor_data) {
|
||||
if (color_ != ui::kDefaultCursorColor) {
|
||||
std::for_each(cursor_data->bitmaps.begin(), cursor_data->bitmaps.end(),
|
||||
[&](SkBitmap& bitmap) {
|
||||
bitmap = wm::GetColorAdjustedBitmap(bitmap, color_);
|
||||
});
|
||||
}
|
||||
// TODO(crbug.com/40175364): consider either passing `scale_` to
|
||||
// `CursorFactory::GetCursorData`, or relying on having called
|
||||
// `CursorFactory::SetDeviceScaleFactor`, instead of appending it here.
|
||||
return ui::CursorData(std::move(cursor_data->bitmaps),
|
||||
std::move(cursor_data->hotspot), scale_);
|
||||
cursor_data->scale_factor = scale_;
|
||||
ApplyColorAndLargeSize(cursor_data.value());
|
||||
return cursor_data;
|
||||
}
|
||||
}
|
||||
|
||||
const int large_cursor_size_in_px =
|
||||
ConvertDipToPixel(large_cursor_size_in_dip_, scale_);
|
||||
|
||||
// TODO(crbug.com/40175364): use the actual `rotation_` if that makes
|
||||
// sense for the current use cases of `GetCursorData` (e.g. Chrome Remote
|
||||
// Desktop, WebRTC and VideoRecordingWatcher).
|
||||
return wm::GetCursorData(type, size_, resource_scale_, std::nullopt,
|
||||
return wm::GetCursorData(type, size_, resource_scale_,
|
||||
size_ == ui::CursorSize::kLarge
|
||||
? std::make_optional(large_cursor_size_in_px)
|
||||
: std::nullopt,
|
||||
display::Display::ROTATE_0, color_);
|
||||
}
|
||||
|
||||
void CursorLoader::UnloadCursors() {
|
||||
image_cursors_.clear();
|
||||
}
|
||||
|
||||
void CursorLoader::ApplyColorAndLargeSize(
|
||||
ui::CursorData& data_in_and_out) const {
|
||||
if (color_ != ui::kDefaultCursorColor) {
|
||||
std::for_each(data_in_and_out.bitmaps.begin(),
|
||||
data_in_and_out.bitmaps.end(), [&](SkBitmap& bitmap) {
|
||||
bitmap = wm::GetColorAdjustedBitmap(bitmap, color_);
|
||||
});
|
||||
}
|
||||
if (size_ == ui::CursorSize::kLarge) {
|
||||
const int large_cursor_size_in_px =
|
||||
ConvertDipToPixel(large_cursor_size_in_dip_, scale_);
|
||||
const gfx::Size cursor_size_in_px =
|
||||
gfx::SkISizeToSize(data_in_and_out.bitmaps[0].dimensions());
|
||||
if (large_cursor_size_in_px != cursor_size_in_px.height()) {
|
||||
const float rescale = static_cast<float>(large_cursor_size_in_px) /
|
||||
static_cast<float>(cursor_size_in_px.height());
|
||||
std::for_each(data_in_and_out.bitmaps.begin(),
|
||||
data_in_and_out.bitmaps.end(), [&](SkBitmap& bitmap) {
|
||||
wm::ScaleAndRotateCursorBitmapAndHotpoint(
|
||||
rescale, display::Display::ROTATE_0, &bitmap,
|
||||
&data_in_and_out.hotspot);
|
||||
});
|
||||
data_in_and_out.scale_factor *= rescale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scoped_refptr<ui::PlatformCursor> CursorLoader::CursorFromType(
|
||||
CursorType type) {
|
||||
// An image cursor is loaded for this type.
|
||||
@ -167,7 +210,11 @@ scoped_refptr<ui::PlatformCursor> CursorLoader::CursorFromType(
|
||||
scoped_refptr<ui::PlatformCursor> CursorLoader::LoadCursorFromAsset(
|
||||
CursorType type) {
|
||||
std::optional<ui::CursorData> cursor_data = wm::GetCursorData(
|
||||
type, size_, resource_scale_, std::nullopt, rotation_, color_);
|
||||
type, size_, resource_scale_,
|
||||
size_ == ui::CursorSize::kLarge ? std::make_optional(ConvertDipToPixel(
|
||||
large_cursor_size_in_dip_, scale_))
|
||||
: std::nullopt,
|
||||
rotation_, color_);
|
||||
if (!cursor_data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -43,11 +43,18 @@ class COMPONENT_EXPORT(UI_WM) CursorLoader
|
||||
// Returns true if the cursor needs to be reset.
|
||||
bool SetDisplay(const display::Display& display);
|
||||
|
||||
// Sets the size of the mouse cursor icon.
|
||||
void SetSize(ui::CursorSize size);
|
||||
|
||||
// Returns the size of the currently loaded cursor.
|
||||
ui::CursorSize size() const { return size_; }
|
||||
|
||||
// Sets the size of the mouse cursor icon.
|
||||
void SetSize(ui::CursorSize size);
|
||||
// Sets the large cursor size in dip. Only used when
|
||||
// `size` is `ui::CursorSize::kLarge`.
|
||||
void SetLargeCursorSizeInDip(int large_cursor_size_in_dip);
|
||||
|
||||
// Returns the large cursor size in dip.
|
||||
int large_cursor_size_in_dip() const { return large_cursor_size_in_dip_; }
|
||||
|
||||
// Sets the color of the cursor.
|
||||
void SetColor(SkColor color);
|
||||
@ -62,6 +69,7 @@ class COMPONENT_EXPORT(UI_WM) CursorLoader
|
||||
private:
|
||||
// Resets the cursor cache.
|
||||
void UnloadCursors();
|
||||
void ApplyColorAndLargeSize(ui::CursorData& data_in_and_out) const;
|
||||
scoped_refptr<ui::PlatformCursor> CursorFromType(ui::mojom::CursorType type);
|
||||
scoped_refptr<ui::PlatformCursor> LoadCursorFromAsset(
|
||||
ui::mojom::CursorType type);
|
||||
@ -88,6 +96,9 @@ class COMPONENT_EXPORT(UI_WM) CursorLoader
|
||||
// The preferred size of the mouse cursor icon.
|
||||
ui::CursorSize size_ = ui::CursorSize::kNormal;
|
||||
|
||||
// The target cursor size in dip for large cursor.
|
||||
int large_cursor_size_in_dip_ = ui::kDefaultLargeCursorSize;
|
||||
|
||||
// The current color set to the mouse cursor icon.
|
||||
SkColor color_ = ui::kDefaultCursorColor;
|
||||
};
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "ui/aura/client/cursor_shape_client.h"
|
||||
#include "ui/base/cursor/cursor.h"
|
||||
#include "ui/base/cursor/cursor_factory.h"
|
||||
#include "ui/base/cursor/cursor_size.h"
|
||||
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
|
||||
#include "ui/base/cursor/platform_cursor.h"
|
||||
#include "ui/base/resource/resource_scale_factor.h"
|
||||
@ -36,12 +37,13 @@ TEST(CursorLoaderTest, InvisibleCursor) {
|
||||
ui::CursorFactory::GetInstance()->GetDefaultCursor(CursorType::kNone));
|
||||
}
|
||||
|
||||
TEST(CursorLoaderTest, GetCursorData) {
|
||||
TEST(CursorLoaderTest, GetCursorDataForDefaultCursors) {
|
||||
// Make sure we always use the fallback cursors, so the test works the same
|
||||
// in all platforms.
|
||||
CursorLoader cursor_loader(/*use_platform_cursors=*/false);
|
||||
|
||||
display::Display display = display::Display::GetDefaultDisplay();
|
||||
|
||||
for (const float scale : {0.8f, 1.0f, 1.25f, 1.5f, 2.0f, 3.0f}) {
|
||||
SCOPED_TRACE(testing::Message() << "scale " << scale);
|
||||
display.set_device_scale_factor(scale);
|
||||
@ -69,17 +71,24 @@ TEST(CursorLoaderTest, GetCursorData) {
|
||||
SCOPED_TRACE(testing::Message()
|
||||
<< "color " << static_cast<int>(cursor_color));
|
||||
cursor_loader.SetColor(cursor_color);
|
||||
|
||||
cursor_loader_data = cursor_loader.GetCursorData(cursor);
|
||||
ASSERT_TRUE(cursor_loader_data);
|
||||
|
||||
// `cursor_loader.large_cursor_size_in_dip()` only takes into effect
|
||||
// when cursor size is large.
|
||||
auto target_cursor_size_in_px =
|
||||
cursor_size == ui::CursorSize::kNormal
|
||||
? std::nullopt
|
||||
: std::make_optional(
|
||||
cursor_loader.large_cursor_size_in_dip() * scale);
|
||||
const auto cursor_data = GetCursorData(
|
||||
cursor.type(), cursor_size, resource_scale, std::nullopt,
|
||||
display.panel_rotation(), cursor_color);
|
||||
cursor.type(), cursor_size, resource_scale,
|
||||
target_cursor_size_in_px, display.panel_rotation(), cursor_color);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
ASSERT_EQ(cursor_loader_data->bitmaps.size(),
|
||||
cursor_data->bitmaps.size());
|
||||
for (size_t i = 0; i < cursor_data->bitmaps.size(); i++) {
|
||||
EXPECT_TRUE(gfx::BitmapsAreEqual(cursor_loader_data->bitmaps[i],
|
||||
ASSERT_TRUE(gfx::BitmapsAreEqual(cursor_loader_data->bitmaps[i],
|
||||
cursor_data->bitmaps[i]));
|
||||
}
|
||||
EXPECT_EQ(cursor_loader_data->hotspot, cursor_data->hotspot);
|
||||
@ -87,27 +96,74 @@ TEST(CursorLoaderTest, GetCursorData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The bitmap pixels of a custom cursor will only update if the cursor color
|
||||
// is changed to a non-default value.
|
||||
const SkBitmap kBitmap = gfx::test::CreateBitmap(20, 20);
|
||||
constexpr gfx::Point kHotspot = gfx::Point(10, 10);
|
||||
const ui::Cursor custom_cursor = ui::Cursor::NewCustom(kBitmap, kHotspot);
|
||||
TEST(CursorLoaderTest, GetCursorDataForCustomCursors) {
|
||||
CursorLoader cursor_loader(/*use_platform_cursors=*/false);
|
||||
|
||||
cursor_loader.SetColor(ui::kDefaultCursorColor);
|
||||
std::optional<ui::CursorData> cursor_data =
|
||||
cursor_loader.GetCursorData(custom_cursor);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
EXPECT_EQ(cursor_data->bitmaps[0].getGenerationID(),
|
||||
kBitmap.getGenerationID());
|
||||
EXPECT_EQ(cursor_data->hotspot, kHotspot);
|
||||
static constexpr int large_cursor_size_in_dip = 50;
|
||||
cursor_loader.SetLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
display::Display display = display::Display::GetDefaultDisplay();
|
||||
|
||||
cursor_loader.SetColor(SK_ColorRED);
|
||||
cursor_data = cursor_loader.GetCursorData(custom_cursor);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
EXPECT_NE(cursor_data->bitmaps[0].getGenerationID(),
|
||||
kBitmap.getGenerationID());
|
||||
EXPECT_EQ(cursor_data->hotspot, kHotspot);
|
||||
for (const float scale : {0.8f, 1.0f, 1.25f, 1.5f, 2.0f, 3.0f}) {
|
||||
SCOPED_TRACE(testing::Message() << "scale " << scale);
|
||||
display.set_device_scale_factor(scale);
|
||||
cursor_loader.SetDisplay(display);
|
||||
for (const ui::CursorSize cursor_size :
|
||||
{ui::CursorSize::kNormal, ui::CursorSize::kLarge}) {
|
||||
SCOPED_TRACE(testing::Message()
|
||||
<< "size " << static_cast<int>(cursor_size));
|
||||
cursor_loader.SetSize(cursor_size);
|
||||
|
||||
// Custom cursor.
|
||||
const SkBitmap custom_bitmap = gfx::test::CreateBitmap(50, 50);
|
||||
static constexpr gfx::Point custom_hotspot = gfx::Point(10, 10);
|
||||
static constexpr float custom_scale = 2.0f;
|
||||
const ui::Cursor custom_cursor =
|
||||
ui::Cursor::NewCustom(custom_bitmap, custom_hotspot, custom_scale);
|
||||
|
||||
// The bitmap pixels of a custom cursor will only update if
|
||||
// (1) the cursor size is large cursor and needs to be scaled,
|
||||
// (2) the cursor color is changed to a non-default value.
|
||||
if (cursor_size == ui::CursorSize::kNormal ||
|
||||
(cursor_size == ui::CursorSize::kLarge &&
|
||||
static_cast<int>(large_cursor_size_in_dip * scale) ==
|
||||
custom_bitmap.dimensions().height())) {
|
||||
// Cursor doesn't need to be scaled.
|
||||
cursor_loader.SetColor(ui::kDefaultCursorColor);
|
||||
std::optional<ui::CursorData> cursor_data =
|
||||
cursor_loader.GetCursorData(custom_cursor);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
// Bitmap pixels won't update since the cursor color is the default
|
||||
// value.
|
||||
EXPECT_EQ(cursor_data->bitmaps[0].getGenerationID(),
|
||||
custom_bitmap.getGenerationID());
|
||||
EXPECT_EQ(cursor_data->hotspot, custom_hotspot);
|
||||
|
||||
cursor_loader.SetColor(SK_ColorRED);
|
||||
cursor_data = cursor_loader.GetCursorData(custom_cursor);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
// Bitmap pixels should update since the cursor color is changed.
|
||||
EXPECT_NE(cursor_data->bitmaps[0].getGenerationID(),
|
||||
custom_bitmap.getGenerationID());
|
||||
EXPECT_EQ(cursor_data->hotspot, custom_hotspot);
|
||||
} else {
|
||||
// Cursor needs to be scaled.
|
||||
cursor_loader.SetColor(ui::kDefaultCursorColor);
|
||||
std::optional<ui::CursorData> cursor_data =
|
||||
cursor_loader.GetCursorData(custom_cursor);
|
||||
ASSERT_TRUE(cursor_data);
|
||||
|
||||
int large_cursor_size_in_px = large_cursor_size_in_dip * scale;
|
||||
float rescale = static_cast<float>(large_cursor_size_in_px) /
|
||||
static_cast<float>(custom_bitmap.dimensions().height());
|
||||
EXPECT_EQ(cursor_data->bitmaps[0].dimensions().height(),
|
||||
large_cursor_size_in_px);
|
||||
EXPECT_EQ(cursor_data->hotspot,
|
||||
gfx::ScaleToFlooredPoint(custom_hotspot, rescale));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test the cursor image cache when fallbacks for system cursors are used.
|
||||
|
@ -11,8 +11,10 @@
|
||||
#include "base/trace_event/trace_event.h"
|
||||
#include "third_party/skia/include/core/SkColor.h"
|
||||
#include "ui/aura/client/cursor_client_observer.h"
|
||||
#include "ui/base/cursor/cursor.h"
|
||||
#include "ui/base/cursor/cursor_size.h"
|
||||
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
|
||||
#include "ui/wm/core/cursor_util.h"
|
||||
#include "ui/wm/core/native_cursor_manager.h"
|
||||
#include "ui/wm/core/native_cursor_manager_delegate.h"
|
||||
|
||||
@ -45,6 +47,11 @@ class CursorState {
|
||||
cursor_size_ = cursor_size;
|
||||
}
|
||||
|
||||
int large_cursor_size_in_dip() const { return large_cursor_size_in_dip_; }
|
||||
void set_large_cursor_size_in_dip(int large_cursor_size_in_dip) {
|
||||
large_cursor_size_in_dip_ = large_cursor_size_in_dip;
|
||||
}
|
||||
|
||||
SkColor cursor_color() const { return cursor_color_; }
|
||||
void set_cursor_color(SkColor cursor_color) { cursor_color_ = cursor_color; }
|
||||
|
||||
@ -72,6 +79,7 @@ class CursorState {
|
||||
gfx::NativeCursor cursor_;
|
||||
bool visible_ = true;
|
||||
ui::CursorSize cursor_size_ = ui::CursorSize::kNormal;
|
||||
int large_cursor_size_in_dip_ = ui::kDefaultLargeCursorSize;
|
||||
SkColor cursor_color_ = ui::kDefaultCursorColor;
|
||||
bool mouse_events_enabled_ = true;
|
||||
|
||||
@ -156,6 +164,23 @@ ui::CursorSize CursorManager::GetCursorSize() const {
|
||||
return current_state_->cursor_size();
|
||||
}
|
||||
|
||||
void CursorManager::SetLargeCursorSizeInDip(int large_cursor_size_in_dip) {
|
||||
large_cursor_size_in_dip =
|
||||
std::clamp(large_cursor_size_in_dip, ui::kMinLargeCursorSize,
|
||||
ui::kMaxLargeCursorSize);
|
||||
|
||||
state_on_unlock_->set_large_cursor_size_in_dip(large_cursor_size_in_dip);
|
||||
if (GetLargeCursorSizeInDip() !=
|
||||
state_on_unlock_->large_cursor_size_in_dip()) {
|
||||
delegate_->SetLargeCursorSizeInDip(
|
||||
state_on_unlock_->large_cursor_size_in_dip(), this);
|
||||
}
|
||||
}
|
||||
|
||||
int CursorManager::GetLargeCursorSizeInDip() const {
|
||||
return current_state_->large_cursor_size_in_dip();
|
||||
}
|
||||
|
||||
void CursorManager::SetCursorColor(SkColor color) {
|
||||
state_on_unlock_->set_cursor_color(color);
|
||||
if (GetCursorColor() != state_on_unlock_->cursor_color()) {
|
||||
@ -274,6 +299,10 @@ void CursorManager::CommitCursorSize(ui::CursorSize cursor_size) {
|
||||
current_state_->set_cursor_size(cursor_size);
|
||||
}
|
||||
|
||||
void CursorManager::CommitLargeCursorSizeInDip(int large_cursor_size_in_dip) {
|
||||
current_state_->set_large_cursor_size_in_dip(large_cursor_size_in_dip);
|
||||
}
|
||||
|
||||
void CursorManager::CommitCursorColor(SkColor color) {
|
||||
current_state_->set_cursor_color(color);
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ class COMPONENT_EXPORT(UI_WM) CursorManager
|
||||
bool IsCursorVisible() const override;
|
||||
void SetCursorSize(ui::CursorSize cursor_size) override;
|
||||
ui::CursorSize GetCursorSize() const override;
|
||||
void SetLargeCursorSizeInDip(int large_cursor_size_in_dip) override;
|
||||
int GetLargeCursorSizeInDip() const override;
|
||||
void SetCursorColor(SkColor color) override;
|
||||
SkColor GetCursorColor() const override;
|
||||
void EnableMouseEvents() override;
|
||||
@ -78,6 +80,7 @@ class COMPONENT_EXPORT(UI_WM) CursorManager
|
||||
void CommitCursor(gfx::NativeCursor cursor) override;
|
||||
void CommitVisibility(bool visible) override;
|
||||
void CommitCursorSize(ui::CursorSize cursor_size) override;
|
||||
void CommitLargeCursorSizeInDip(int large_cursor_size_in_dip) override;
|
||||
void CommitCursorColor(SkColor color) override;
|
||||
void CommitMouseEventsEnabled(bool enabled) override;
|
||||
void CommitSystemCursorSize(const gfx::Size& cursor_size) override;
|
||||
|
@ -42,6 +42,12 @@ class TestingCursorManager : public wm::NativeCursorManager {
|
||||
delegate->CommitCursorSize(cursor_size);
|
||||
}
|
||||
|
||||
void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
wm::NativeCursorManagerDelegate* delegate) override {
|
||||
delegate->CommitLargeCursorSizeInDip(large_cursor_size_in_dip);
|
||||
}
|
||||
|
||||
void SetCursorColor(SkColor color,
|
||||
wm::NativeCursorManagerDelegate* delegate) override {
|
||||
NOTIMPLEMENTED();
|
||||
|
@ -109,7 +109,7 @@ TEST(CursorUtil, GetCursorData) {
|
||||
<< "size " << base::checked_cast<int>(scale));
|
||||
for (const auto& test : kCursorTestCases) {
|
||||
SCOPED_TRACE(test.cursor);
|
||||
constexpr auto kDefaultRotation = display::Display::ROTATE_0;
|
||||
static constexpr auto kDefaultRotation = display::Display::ROTATE_0;
|
||||
const auto pointer_data =
|
||||
GetCursorData(test.cursor, size, scale, std::nullopt,
|
||||
kDefaultRotation, SK_ColorBLACK);
|
||||
@ -130,6 +130,56 @@ TEST(CursorUtil, GetCursorData) {
|
||||
}
|
||||
}
|
||||
|
||||
// Tests cursor bitmap is correct after size rescaling.
|
||||
TEST(CursorUtil, GetCursorDataWithTargetCursorSize) {
|
||||
// Data from `kLargeCursorResourceData`.
|
||||
constexpr struct {
|
||||
CursorType cursor;
|
||||
gfx::Size size; // large cursor size in dip
|
||||
gfx::Point hotspot[2]; // hotspot in px, indexed by scale.
|
||||
} kCursorTestCases[] = {{CursorType::kPointer,
|
||||
gfx::Size(64, 64),
|
||||
{gfx::Point(10, 10), gfx::Point(20, 20)}},
|
||||
{CursorType::kWait,
|
||||
gfx::Size(16, 16),
|
||||
{gfx::Point(7, 7), gfx::Point(14, 14)}}};
|
||||
|
||||
for (const float scale : {0.8f, 1.0f, 1.3f, 1.5f, 2.0f, 2.5f}) {
|
||||
SCOPED_TRACE(testing::Message() << "scale " << scale);
|
||||
for (const auto& test : kCursorTestCases) {
|
||||
SCOPED_TRACE(test.cursor);
|
||||
static constexpr auto kDefaultRotation = display::Display::ROTATE_0;
|
||||
for (const auto& target_cursor_size_in_px :
|
||||
{ui::kMinLargeCursorSize, ui::kMaxLargeCursorSize}) {
|
||||
const float resource_scale = ui::GetScaleForResourceScaleFactor(
|
||||
ui::GetSupportedResourceScaleFactorForRescale(scale));
|
||||
const auto pointer_data =
|
||||
GetCursorData(test.cursor, ui::CursorSize::kLarge, scale,
|
||||
std::make_optional(target_cursor_size_in_px),
|
||||
kDefaultRotation, SK_ColorBLACK);
|
||||
ASSERT_TRUE(pointer_data);
|
||||
ASSERT_GT(pointer_data->bitmaps.size(), 0u);
|
||||
|
||||
// `target_cursor_size_in_px` should be the height of the final size of
|
||||
// cursor.
|
||||
const gfx::Size actual_cursor_size_in_px =
|
||||
gfx::SkISizeToSize(pointer_data->bitmaps[0].dimensions());
|
||||
EXPECT_EQ(actual_cursor_size_in_px.height(), target_cursor_size_in_px);
|
||||
|
||||
const gfx::Point actual_hotspot_in_px = pointer_data->hotspot;
|
||||
const float rescale = static_cast<float>(target_cursor_size_in_px) /
|
||||
static_cast<float>(test.size.height());
|
||||
const gfx::Point expected_hotspot_in_dip = gfx::ScaleToFlooredPoint(
|
||||
test.hotspot[base::checked_cast<int>(resource_scale) - 1],
|
||||
1 / resource_scale);
|
||||
const gfx::Point expected_hotspot_in_px =
|
||||
gfx::ScaleToFlooredPoint(expected_hotspot_in_dip, rescale);
|
||||
EXPECT_EQ(actual_hotspot_in_px, expected_hotspot_in_px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests cursor bitmap is correct after applying color on it.
|
||||
TEST(CursorUtil, GetCursorDataWithColor) {
|
||||
const struct {
|
||||
|
@ -49,6 +49,11 @@ class COMPONENT_EXPORT(UI_WM) NativeCursorManager {
|
||||
virtual void SetCursorSize(ui::CursorSize cursor_size,
|
||||
NativeCursorManagerDelegate* delegate) = 0;
|
||||
|
||||
// A request to set the ui::CursorSize::kLarge dimensions in DIPs.
|
||||
virtual void SetLargeCursorSizeInDip(
|
||||
int large_cursor_size_in_dip,
|
||||
NativeCursorManagerDelegate* delegate) = 0;
|
||||
|
||||
// A request to set whether mouse events are disabled. At minimum,
|
||||
// implementer should call NativeCursorManagerDelegate::
|
||||
// CommitMouseEventsEnabled() with whether mouse events are actually enabled.
|
||||
|
@ -33,6 +33,7 @@ class COMPONENT_EXPORT(UI_WM) NativeCursorManagerDelegate {
|
||||
virtual void CommitCursor(gfx::NativeCursor cursor) = 0;
|
||||
virtual void CommitVisibility(bool visible) = 0;
|
||||
virtual void CommitCursorSize(ui::CursorSize cursor_size) = 0;
|
||||
virtual void CommitLargeCursorSizeInDip(int large_cursor_size_in_dip) = 0;
|
||||
virtual void CommitCursorColor(SkColor color) = 0;
|
||||
virtual void CommitMouseEventsEnabled(bool enabled) = 0;
|
||||
virtual void CommitSystemCursorSize(const gfx::Size& cursor_size) = 0;
|
||||
|
Reference in New Issue
Block a user