blob: 5073af765ae2544eeb03c8ac87af8d623542861f [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include "build/build_config.h"
#include "content/common/cursors/webcursor.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace content {
namespace {
// Creates a basic bitmap for testing with the given width and height.
SkBitmap CreateTestBitmap(int width, int height) {
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height);
bitmap.eraseColor(SK_ColorRED);
return bitmap;
}
TEST(WebCursorTest, DefaultConstructor) {
WebCursor webcursor;
EXPECT_EQ(ui::mojom::CursorType::kNull, webcursor.cursor().type());
EXPECT_TRUE(webcursor.cursor().custom_bitmap().isNull());
EXPECT_TRUE(webcursor.cursor().custom_hotspot().IsOrigin());
EXPECT_EQ(1.f, webcursor.cursor().image_scale_factor());
}
TEST(WebCursorTest, WebCursorCursorConstructor) {
ui::Cursor cursor(ui::mojom::CursorType::kHand);
WebCursor webcursor(cursor);
EXPECT_EQ(cursor, webcursor.cursor());
}
TEST(WebCursorTest, WebCursorCursorConstructorCustom) {
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_bitmap(CreateTestBitmap(32, 32));
cursor.set_custom_hotspot(gfx::Point(10, 20));
cursor.set_image_scale_factor(2.f);
WebCursor webcursor(cursor);
EXPECT_EQ(cursor, webcursor.cursor());
#if defined(USE_AURA)
// Test if the custom cursor is correctly cached and updated
// on aura platform.
gfx::NativeCursor native_cursor = webcursor.GetNativeCursor();
EXPECT_EQ(gfx::Point(5, 10), native_cursor.custom_hotspot());
EXPECT_TRUE(webcursor.has_custom_cursor_for_test());
webcursor.SetCursor(cursor);
EXPECT_FALSE(webcursor.has_custom_cursor_for_test());
webcursor.GetNativeCursor();
EXPECT_TRUE(webcursor.has_custom_cursor_for_test());
#if defined(USE_OZONE)
// Test if the rotating custom cursor works correctly.
display::Display display;
display.set_panel_rotation(display::Display::ROTATE_90);
webcursor.SetDisplayInfo(display);
EXPECT_FALSE(webcursor.has_custom_cursor_for_test());
native_cursor = webcursor.GetNativeCursor();
EXPECT_TRUE(webcursor.has_custom_cursor_for_test());
// Hotspot should be scaled & rotated. We're using the icon created for 2.0,
// on the display with dsf=1.0, so the host spot should be
// ((32 - 20) / 2, 10 / 2) = (6, 5).
EXPECT_EQ(gfx::Point(6, 5), native_cursor.custom_hotspot());
#endif
#endif
}
TEST(WebCursorTest, CopyConstructorType) {
ui::Cursor cursor(ui::mojom::CursorType::kHand);
WebCursor webcursor(cursor);
WebCursor copy(webcursor);
EXPECT_EQ(webcursor, copy);
}
TEST(WebCursorTest, CopyConstructorCustom) {
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_bitmap(CreateTestBitmap(32, 32));
cursor.set_custom_hotspot(gfx::Point(10, 20));
cursor.set_image_scale_factor(1.5f);
WebCursor webcursor(cursor);
WebCursor copy(webcursor);
EXPECT_EQ(webcursor, copy);
}
TEST(WebCursorTest, ClampHotspot) {
// Initialize a cursor with an invalid hotspot; it should be clamped.
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_hotspot(gfx::Point(100, 100));
cursor.set_custom_bitmap(CreateTestBitmap(5, 7));
WebCursor webcursor(cursor);
EXPECT_EQ(gfx::Point(4, 6), webcursor.cursor().custom_hotspot());
// SetCursor should also clamp the hotspot.
EXPECT_TRUE(webcursor.SetCursor(cursor));
EXPECT_EQ(gfx::Point(4, 6), webcursor.cursor().custom_hotspot());
}
TEST(WebCursorTest, SetCursor) {
WebCursor webcursor;
EXPECT_TRUE(webcursor.SetCursor(ui::Cursor()));
EXPECT_TRUE(webcursor.SetCursor(ui::Cursor(ui::mojom::CursorType::kHand)));
EXPECT_TRUE(webcursor.SetCursor(ui::Cursor(ui::mojom::CursorType::kCustom)));
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_bitmap(CreateTestBitmap(32, 32));
cursor.set_custom_hotspot(gfx::Point(10, 20));
cursor.set_image_scale_factor(1.5f);
EXPECT_TRUE(webcursor.SetCursor(cursor));
// SetCursor should return false when the scale factor is too small.
cursor.set_image_scale_factor(0.001f);
EXPECT_FALSE(webcursor.SetCursor(cursor));
// SetCursor should return false when the scale factor is too large.
cursor.set_image_scale_factor(1000.f);
EXPECT_FALSE(webcursor.SetCursor(cursor));
// SetCursor should return false when the image width is too large.
cursor.set_image_scale_factor(1.f);
cursor.set_custom_bitmap(CreateTestBitmap(1025, 3));
EXPECT_FALSE(webcursor.SetCursor(cursor));
// SetCursor should return false when the image height is too large.
cursor.set_custom_bitmap(CreateTestBitmap(3, 1025));
EXPECT_FALSE(webcursor.SetCursor(cursor));
// SetCursor should return false when the scaled image width is too large.
cursor.set_image_scale_factor(0.02f);
cursor.set_custom_bitmap(CreateTestBitmap(50, 5));
EXPECT_FALSE(webcursor.SetCursor(cursor));
// SetCursor should return false when the scaled image height is too large.
cursor.set_image_scale_factor(0.1f);
cursor.set_custom_bitmap(CreateTestBitmap(5, 200));
EXPECT_FALSE(webcursor.SetCursor(cursor));
}
#if defined(USE_AURA)
TEST(WebCursorTest, CursorScaleFactor) {
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_hotspot(gfx::Point(0, 1));
cursor.set_image_scale_factor(2.0f);
cursor.set_custom_bitmap(CreateTestBitmap(128, 128));
WebCursor webcursor(cursor);
display::Display display;
display.set_device_scale_factor(4.2f);
webcursor.SetDisplayInfo(display);
#if defined(USE_OZONE)
// For Ozone cursors, the size of the cursor is capped at 64px, and this is
// enforce through the calculated scale factor.
EXPECT_EQ(0.5f, webcursor.GetNativeCursor().image_scale_factor());
#else
EXPECT_EQ(2.1f, webcursor.GetNativeCursor().image_scale_factor());
#endif
// Test that the Display dsf is copied.
WebCursor copy(webcursor);
EXPECT_EQ(webcursor.GetNativeCursor().image_scale_factor(),
copy.GetNativeCursor().image_scale_factor());
}
TEST(WebCursorTest, UnscaledImageCopy) {
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_hotspot(gfx::Point(0, 1));
cursor.set_custom_bitmap(CreateTestBitmap(2, 2));
WebCursor webcursor(cursor);
SkBitmap copy;
gfx::Point hotspot;
float dsf = 0.f;
webcursor.CreateScaledBitmapAndHotspotFromCustomData(&copy, &hotspot, &dsf);
EXPECT_EQ(1.f, dsf);
EXPECT_EQ(2, copy.width());
EXPECT_EQ(2, copy.height());
EXPECT_EQ(0, hotspot.x());
EXPECT_EQ(1, hotspot.y());
}
#endif
#if defined(OS_WIN)
void ScaleCursor(float scale, int hotspot_x, int hotspot_y) {
ui::Cursor cursor(ui::mojom::CursorType::kCustom);
cursor.set_custom_hotspot(gfx::Point(hotspot_x, hotspot_y));
cursor.set_custom_bitmap(CreateTestBitmap(10, 10));
WebCursor webcursor(cursor);
display::Display display;
display.set_device_scale_factor(scale);
webcursor.SetDisplayInfo(display);
HCURSOR windows_cursor_handle = webcursor.GetNativeCursor().platform();
EXPECT_NE(nullptr, windows_cursor_handle);
ICONINFO windows_icon_info;
EXPECT_TRUE(GetIconInfo(windows_cursor_handle, &windows_icon_info));
EXPECT_FALSE(windows_icon_info.fIcon);
EXPECT_EQ(static_cast<DWORD>(scale * hotspot_x), windows_icon_info.xHotspot);
EXPECT_EQ(static_cast<DWORD>(scale * hotspot_y), windows_icon_info.yHotspot);
}
TEST(WebCursorTest, WindowsCursorScaledAtHiDpi) {
ScaleCursor(2.0f, 4, 6);
ScaleCursor(1.5f, 2, 8);
ScaleCursor(1.25f, 3, 7);
}
#endif
} // namespace
} // namespace content