| // Copyright 2021 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 "ui/base/cursor/cursor_loader.h" |
| |
| #include <map> |
| #include <vector> |
| |
| #include "base/check.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/time/time.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/cursor_util.h" |
| #include "ui/base/cursor/cursors_aura.h" |
| #include "ui/base/cursor/mojom/cursor_type.mojom.h" |
| #include "ui/base/cursor/platform_cursor.h" |
| #include "ui/gfx/geometry/point.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| constexpr mojom::CursorType kAnimatedCursorTypes[] = { |
| mojom::CursorType::kWait, mojom::CursorType::kProgress}; |
| |
| constexpr base::TimeDelta kAnimatedCursorFrameDelay = base::Milliseconds(25); |
| |
| } // namespace |
| |
| CursorLoader::CursorLoader(bool use_platform_cursors) |
| : use_platform_cursors_(use_platform_cursors), |
| factory_(CursorFactory::GetInstance()) { |
| factory_->AddObserver(this); |
| } |
| |
| CursorLoader::~CursorLoader() { |
| factory_->RemoveObserver(this); |
| UnloadCursors(); |
| } |
| |
| void CursorLoader::OnThemeLoaded() { |
| UnloadCursors(); |
| } |
| |
| void CursorLoader::UnloadCursors() { |
| image_cursors_.clear(); |
| } |
| |
| bool CursorLoader::SetDisplayData(display::Display::Rotation rotation, |
| float scale) { |
| if (rotation_ == rotation && scale_ == scale) |
| return false; |
| |
| rotation_ = rotation; |
| scale_ = scale; |
| UnloadCursors(); |
| if (use_platform_cursors_) |
| factory_->SetDeviceScaleFactor(scale_); |
| return true; |
| } |
| |
| void CursorLoader::SetSize(CursorSize size) { |
| if (size_ == size) |
| return; |
| |
| size_ = size; |
| UnloadCursors(); |
| } |
| |
| void CursorLoader::SetPlatformCursor(Cursor* cursor) { |
| DCHECK(cursor); |
| |
| // The platform cursor was already set via WebCursor::GetNativeCursor. |
| if (cursor->type() == mojom::CursorType::kCustom) |
| return; |
| cursor->set_image_scale_factor(scale()); |
| cursor->SetPlatformCursor(CursorFromType(cursor->type())); |
| } |
| |
| void CursorLoader::LoadImageCursor(mojom::CursorType type, |
| int resource_id, |
| const gfx::Point& hot) { |
| gfx::Point hotspot = hot; |
| if (base::ranges::count(kAnimatedCursorTypes, type) == 0) { |
| SkBitmap bitmap; |
| GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap); |
| image_cursors_[type] = factory_->CreateImageCursor(type, bitmap, hotspot); |
| } else { |
| std::vector<SkBitmap> bitmaps; |
| GetAnimatedCursorBitmaps(resource_id, scale(), rotation(), &hotspot, |
| &bitmaps); |
| image_cursors_[type] = factory_->CreateAnimatedCursor( |
| type, bitmaps, hotspot, kAnimatedCursorFrameDelay); |
| } |
| } |
| |
| scoped_refptr<PlatformCursor> CursorLoader::CursorFromType( |
| mojom::CursorType type) { |
| // An image cursor is loaded for this type. |
| if (image_cursors_.count(type)) |
| return image_cursors_[type]; |
| |
| // Check if there's a default platform cursor available. |
| // For the none cursor, we also need to use the platform factory to take |
| // into account the different ways of creating an invisible cursor. |
| scoped_refptr<PlatformCursor> cursor; |
| if (use_platform_cursors_ || type == mojom::CursorType::kNone) { |
| cursor = factory_->GetDefaultCursor(type); |
| if (cursor) |
| return cursor; |
| LOG(ERROR) << "Failed to load a platform cursor of type " << type; |
| } |
| |
| // Loads the default Aura cursor bitmap for the cursor type. Falls back on |
| // pointer cursor if this fails. |
| cursor = LoadCursorFromAsset(type); |
| if (!cursor && type != mojom::CursorType::kPointer) { |
| cursor = CursorFromType(mojom::CursorType::kPointer); |
| image_cursors_[type] = cursor; |
| } |
| DCHECK(cursor) << "Failed to load a bitmap for the pointer cursor."; |
| return cursor; |
| } |
| |
| scoped_refptr<PlatformCursor> CursorLoader::LoadCursorFromAsset( |
| mojom::CursorType type) { |
| int resource_id; |
| gfx::Point hotspot; |
| if (GetCursorDataFor(size(), type, scale(), &resource_id, &hotspot)) { |
| LoadImageCursor(type, resource_id, hotspot); |
| return image_cursors_[type]; |
| } |
| return nullptr; |
| } |
| |
| } // namespace ui |