910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// 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_factory.h"

#include <ostream>

#include "base/check.h"
#include "base/check_op.h"
#include "base/memory/scoped_refptr.h"
#include "base/notimplemented.h"
#include "base/notreached.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/cursor/platform_cursor.h"

namespace ui {

namespace {

CursorFactory* g_instance = nullptr;

}  // namespace

CursorFactoryObserver::~CursorFactoryObserver() = default;

CursorFactory::CursorFactory() {
  DCHECK(!g_instance) << "There should only be a single CursorFactory.";
  g_instance = this;
}

CursorFactory::~CursorFactory() {
  DCHECK_EQ(g_instance, this);
  g_instance = nullptr;
}

CursorFactory* CursorFactory::GetInstance() {
  DCHECK(g_instance);
  return g_instance;
}

void CursorFactory::AddObserver(CursorFactoryObserver* observer) {
  observers_.AddObserver(observer);
}

void CursorFactory::RemoveObserver(CursorFactoryObserver* observer) {
  observers_.RemoveObserver(observer);
}

void CursorFactory::NotifyObserversOnThemeLoaded() {
  observers_.Notify(&CursorFactoryObserver::OnThemeLoaded);
}

scoped_refptr<PlatformCursor> CursorFactory::GetDefaultCursor(
    mojom::CursorType type) {
  NOTIMPLEMENTED();
  return nullptr;
}

scoped_refptr<PlatformCursor> CursorFactory::GetDefaultCursor(
    mojom::CursorType type,
    float scale) {
  // If the backend doesn't provide its own implementation of
  // GetDefaultCursor(type, scale) it is assumed that the cursor objects
  // returned by GetDefaultCursor(type) are independent of display scale values.
  return GetDefaultCursor(type);
}

scoped_refptr<PlatformCursor> CursorFactory::CreateImageCursor(
    mojom::CursorType type,
    const SkBitmap& bitmap,
    const gfx::Point& hotspot,
    float scale) {
  NOTIMPLEMENTED();
  return nullptr;
}

std::optional<CursorData> CursorFactory::GetCursorData(mojom::CursorType type) {
  return std::nullopt;
}

scoped_refptr<PlatformCursor> CursorFactory::CreateAnimatedCursor(
    mojom::CursorType type,
    const std::vector<SkBitmap>& bitmaps,
    const gfx::Point& hotspot,
    float scale,
    base::TimeDelta frame_delay) {
  NOTIMPLEMENTED();
  return nullptr;
}

void CursorFactory::ObserveThemeChanges() {
  NOTIMPLEMENTED();
}

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

// Returns a cursor name compatible with either X11 or the FreeDesktop.org
// cursor spec ([1] and [2]), followed by fallbacks that can work as
// replacements in some environments where the original may not be available
// (e.g. desktop environments other than GNOME and KDE).
//
// TODO(hferreiro): each list starts with the FreeDesktop.org icon name but
// "ns-resize", "ew-resize", "nesw-resize", "nwse-resize", "grab", "grabbing",
// which were not available in older versions of Breeze, the default KDE theme.
//
// [1]
// https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#x_font_cursors
// [2] https://www.freedesktop.org/wiki/Specifications/cursor-spec/
std::vector<std::string> CursorNamesFromType(mojom::CursorType type) {
  switch (type) {
    case mojom::CursorType::kMove:
      // Returning "move" is the correct thing here, but Blink doesn't make a
      // distinction between move and all-scroll.  Other platforms use a cursor
      // more consistent with all-scroll, so use that.
    case mojom::CursorType::kMiddlePanning:
    case mojom::CursorType::kMiddlePanningVertical:
    case mojom::CursorType::kMiddlePanningHorizontal:
      return {"all-scroll", "fleur"};
    case mojom::CursorType::kEastPanning:
    case mojom::CursorType::kEastResize:
      return {"e-resize", "right_side"};
    case mojom::CursorType::kNorthPanning:
    case mojom::CursorType::kNorthResize:
      return {"n-resize", "top_side"};
    case mojom::CursorType::kNorthEastPanning:
    case mojom::CursorType::kNorthEastResize:
      return {"ne-resize", "top_right_corner"};
    case mojom::CursorType::kNorthWestPanning:
    case mojom::CursorType::kNorthWestResize:
      return {"nw-resize", "top_left_corner"};
    case mojom::CursorType::kSouthPanning:
    case mojom::CursorType::kSouthResize:
      return {"s-resize", "bottom_side"};
    case mojom::CursorType::kSouthEastPanning:
    case mojom::CursorType::kSouthEastResize:
      return {"se-resize", "bottom_right_corner"};
    case mojom::CursorType::kSouthWestPanning:
    case mojom::CursorType::kSouthWestResize:
      return {"sw-resize", "bottom_left_corner"};
    case mojom::CursorType::kWestPanning:
    case mojom::CursorType::kWestResize:
      return {"w-resize", "left_side"};
    case mojom::CursorType::kNone:
      return {};
    case mojom::CursorType::kGrab:
      return {"openhand", "grab", "hand1"};
    case mojom::CursorType::kGrabbing:
      return {"closedhand", "grabbing", "hand2"};
    case mojom::CursorType::kCross:
      return {"crosshair", "cross"};
    case mojom::CursorType::kHand:
      return {"pointer", "hand", "hand2"};
    case mojom::CursorType::kIBeam:
      return {"text", "xterm"};
    case mojom::CursorType::kProgress:
      return {"progress", "left_ptr_watch", "watch"};
    case mojom::CursorType::kWait:
      return {"wait", "watch"};
    case mojom::CursorType::kHelp:
      return {"help"};
    case mojom::CursorType::kNorthSouthResize:
      return {"sb_v_double_arrow", "ns-resize"};
    case mojom::CursorType::kEastWestResize:
      return {"sb_h_double_arrow", "ew-resize"};
    case mojom::CursorType::kColumnResize:
      return {"col-resize", "sb_h_double_arrow"};
    case mojom::CursorType::kRowResize:
      return {"row-resize", "sb_v_double_arrow"};
    case mojom::CursorType::kNorthEastSouthWestResize:
      return {"size_bdiag", "nesw-resize", "fd_double_arrow"};
    case mojom::CursorType::kNorthWestSouthEastResize:
      return {"size_fdiag", "nwse-resize", "bd_double_arrow"};
    case mojom::CursorType::kVerticalText:
      return {"vertical-text"};
    case mojom::CursorType::kZoomIn:
      return {"zoom-in"};
    case mojom::CursorType::kZoomOut:
      return {"zoom-out"};
    case mojom::CursorType::kCell:
      return {"cell", "plus"};
    case mojom::CursorType::kContextMenu:
      return {"context-menu"};
    case mojom::CursorType::kAlias:
      return {"alias"};
    case mojom::CursorType::kNoDrop:
      return {"no-drop"};
    case mojom::CursorType::kCopy:
      return {"copy"};
    case mojom::CursorType::kNotAllowed:
    case mojom::CursorType::kNorthSouthNoResize:
    case mojom::CursorType::kEastWestNoResize:
    case mojom::CursorType::kNorthEastSouthWestNoResize:
    case mojom::CursorType::kNorthWestSouthEastNoResize:
      return {"not-allowed", "crossed_circle"};
    case mojom::CursorType::kDndNone:
      return {"dnd-none", "hand2"};
    case mojom::CursorType::kDndMove:
      return {"dnd-move", "hand2"};
    case mojom::CursorType::kDndCopy:
      return {"dnd-copy", "hand2"};
    case mojom::CursorType::kDndLink:
      return {"dnd-link", "hand2"};
    case mojom::CursorType::kCustom:
      // kCustom is for custom image cursors. The platform cursor will be set
      // at WebCursor::GetNativeCursor().
      NOTREACHED();
    case mojom::CursorType::kNull:
    case mojom::CursorType::kPointer:
      return {"left_ptr"};
  }
  NOTREACHED();
}

#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

}  // namespace ui