• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/base/cursor/cursors_aura.h"
6 
7 #include "grit/ui_resources.h"
8 #include "third_party/skia/include/core/SkBitmap.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/image/image_skia.h"
11 #include "ui/gfx/point.h"
12 
13 namespace ui {
14 namespace {
15 
16 struct HotPoint {
17   int x;
18   int y;
19 };
20 
21 struct CursorData {
22   int id;
23   int resource_id;
24   HotPoint hot_1x;
25   HotPoint hot_2x;
26 };
27 
28 struct CursorSet {
29   const CursorSetType id;
30   const CursorData* cursors;
31   const int length;
32   const CursorData* animated_cursors;
33   const int animated_length;
34 };
35 
36 const CursorData kNormalCursors[] = {
37   {ui::kCursorNull, IDR_AURA_CURSOR_PTR, {4, 4}, {8, 9}},
38   {ui::kCursorPointer, IDR_AURA_CURSOR_PTR, {4, 4}, {8, 9}},
39   {ui::kCursorNoDrop, IDR_AURA_CURSOR_NO_DROP, {9, 9}, {18, 18}},
40   {ui::kCursorNotAllowed, IDR_AURA_CURSOR_NO_DROP, {9, 9}, {18, 18}},
41   {ui::kCursorCopy, IDR_AURA_CURSOR_COPY, {9, 9}, {18, 18}},
42   {ui::kCursorHand, IDR_AURA_CURSOR_HAND, {9, 4}, {19, 8}},
43   {ui::kCursorMove, IDR_AURA_CURSOR_MOVE, {11, 11}, {23, 23}},
44   {ui::kCursorNorthEastResize, IDR_AURA_CURSOR_NORTH_EAST_RESIZE,
45    {12, 11}, {25, 23}},
46   {ui::kCursorSouthWestResize, IDR_AURA_CURSOR_SOUTH_WEST_RESIZE,
47    {12, 11}, {25, 23}},
48   {ui::kCursorSouthEastResize, IDR_AURA_CURSOR_SOUTH_EAST_RESIZE,
49    {11, 11}, {24, 23}},
50   {ui::kCursorNorthWestResize, IDR_AURA_CURSOR_NORTH_WEST_RESIZE,
51    {11, 11}, {24, 23}},
52   {ui::kCursorNorthResize, IDR_AURA_CURSOR_NORTH_RESIZE, {11, 12}, {23, 23}},
53   {ui::kCursorSouthResize, IDR_AURA_CURSOR_SOUTH_RESIZE, {11, 12}, {23, 23}},
54   {ui::kCursorEastResize, IDR_AURA_CURSOR_EAST_RESIZE, {12, 11}, {25, 23}},
55   {ui::kCursorWestResize, IDR_AURA_CURSOR_WEST_RESIZE, {12, 11}, {25, 23}},
56   {ui::kCursorIBeam, IDR_AURA_CURSOR_IBEAM, {12, 12}, {24, 25}},
57   {ui::kCursorAlias, IDR_AURA_CURSOR_ALIAS, {8, 6}, {15, 11}},
58   {ui::kCursorCell, IDR_AURA_CURSOR_CELL, {11, 11}, {24, 23}},
59   {ui::kCursorContextMenu, IDR_AURA_CURSOR_CONTEXT_MENU, {4, 4}, {8, 9}},
60   {ui::kCursorCross, IDR_AURA_CURSOR_CROSSHAIR, {12, 12}, {25, 23}},
61   {ui::kCursorHelp, IDR_AURA_CURSOR_HELP, {4, 4}, {8, 9}},
62   {ui::kCursorVerticalText, IDR_AURA_CURSOR_XTERM_HORIZ, {12, 11}, {26, 23}},
63   {ui::kCursorZoomIn, IDR_AURA_CURSOR_ZOOM_IN, {10, 10}, {20, 20}},
64   {ui::kCursorZoomOut, IDR_AURA_CURSOR_ZOOM_OUT, {10, 10}, {20, 20}},
65   {ui::kCursorRowResize, IDR_AURA_CURSOR_ROW_RESIZE, {11, 12}, {23, 23}},
66   {ui::kCursorColumnResize, IDR_AURA_CURSOR_COL_RESIZE, {12, 11}, {25, 23}},
67   {ui::kCursorEastWestResize, IDR_AURA_CURSOR_EAST_WEST_RESIZE,
68    {12, 11}, {25, 23}},
69   {ui::kCursorNorthSouthResize, IDR_AURA_CURSOR_NORTH_SOUTH_RESIZE,
70    {11, 12}, {23, 23}},
71   {ui::kCursorNorthEastSouthWestResize,
72    IDR_AURA_CURSOR_NORTH_EAST_SOUTH_WEST_RESIZE, {12, 11}, {25, 23}},
73   {ui::kCursorNorthWestSouthEastResize,
74    IDR_AURA_CURSOR_NORTH_WEST_SOUTH_EAST_RESIZE, {11, 11}, {24, 23}},
75   {ui::kCursorGrab, IDR_AURA_CURSOR_GRAB, {8, 5}, {16, 10}},
76   {ui::kCursorGrabbing, IDR_AURA_CURSOR_GRABBING, {9, 9}, {18, 18}},
77 };
78 
79 const CursorData kLargeCursors[] = {
80   // The 2x hotspots should be double of the 1x, even though the cursors are
81   // shown as same size as 1x (64x64), because in 2x dpi screen, the 1x large
82   // cursor assets (64x64) are internally enlarged to the double size (128x128)
83   // by ResourceBundleImageSource.
84   {ui::kCursorNull, IDR_AURA_CURSOR_BIG_PTR, {10, 10}, {20, 20}},
85   {ui::kCursorPointer, IDR_AURA_CURSOR_BIG_PTR, {10, 10}, {20, 20}},
86   {ui::kCursorNoDrop, IDR_AURA_CURSOR_BIG_NO_DROP, {10, 10}, {20, 20}},
87   {ui::kCursorNotAllowed, IDR_AURA_CURSOR_BIG_NO_DROP, {10, 10}, {20, 20}},
88   {ui::kCursorCopy, IDR_AURA_CURSOR_BIG_COPY, {10, 10}, {20, 20}},
89   {ui::kCursorHand, IDR_AURA_CURSOR_BIG_HAND, {25, 7}, {50, 14}},
90   {ui::kCursorMove, IDR_AURA_CURSOR_BIG_MOVE, {32, 31}, {64, 62}},
91   {ui::kCursorNorthEastResize, IDR_AURA_CURSOR_BIG_NORTH_EAST_RESIZE,
92    {31, 28}, {62, 56}},
93   {ui::kCursorSouthWestResize, IDR_AURA_CURSOR_BIG_SOUTH_WEST_RESIZE,
94    {31, 28}, {62, 56}},
95   {ui::kCursorSouthEastResize, IDR_AURA_CURSOR_BIG_SOUTH_EAST_RESIZE,
96    {28, 28}, {56, 56}},
97   {ui::kCursorNorthWestResize, IDR_AURA_CURSOR_BIG_NORTH_WEST_RESIZE,
98    {28, 28}, {56, 56}},
99   {ui::kCursorNorthResize, IDR_AURA_CURSOR_BIG_NORTH_RESIZE,
100    {29, 32}, {58, 64}},
101   {ui::kCursorSouthResize, IDR_AURA_CURSOR_BIG_SOUTH_RESIZE,
102    {29, 32}, {58, 64}},
103   {ui::kCursorEastResize, IDR_AURA_CURSOR_BIG_EAST_RESIZE, {35, 29}, {70, 58}},
104   {ui::kCursorWestResize, IDR_AURA_CURSOR_BIG_WEST_RESIZE, {35, 29}, {70, 58}},
105   {ui::kCursorIBeam, IDR_AURA_CURSOR_BIG_IBEAM, {30, 32}, {60, 64}},
106   {ui::kCursorAlias, IDR_AURA_CURSOR_BIG_ALIAS, {19, 11}, {38, 22}},
107   {ui::kCursorCell, IDR_AURA_CURSOR_BIG_CELL, {30, 30}, {60, 60}},
108   {ui::kCursorContextMenu, IDR_AURA_CURSOR_BIG_CONTEXT_MENU,
109    {11, 11}, {22, 22}},
110   {ui::kCursorCross, IDR_AURA_CURSOR_BIG_CROSSHAIR, {31, 30}, {62, 60}},
111   {ui::kCursorHelp, IDR_AURA_CURSOR_BIG_HELP, {10, 11}, {20, 22}},
112   {ui::kCursorVerticalText, IDR_AURA_CURSOR_BIG_XTERM_HORIZ,
113    {32, 30}, {64, 60}},
114   {ui::kCursorZoomIn, IDR_AURA_CURSOR_BIG_ZOOM_IN, {25, 26}, {50, 52}},
115   {ui::kCursorZoomOut, IDR_AURA_CURSOR_BIG_ZOOM_OUT, {26, 26}, {52, 52}},
116   {ui::kCursorRowResize, IDR_AURA_CURSOR_BIG_ROW_RESIZE, {29, 32}, {58, 64}},
117   {ui::kCursorColumnResize, IDR_AURA_CURSOR_BIG_COL_RESIZE, {35, 29}, {70, 58}},
118   {ui::kCursorEastWestResize, IDR_AURA_CURSOR_BIG_EAST_WEST_RESIZE,
119    {35, 29}, {70, 58}},
120   {ui::kCursorNorthSouthResize, IDR_AURA_CURSOR_BIG_NORTH_SOUTH_RESIZE,
121    {29, 32}, {58, 64}},
122   {ui::kCursorNorthEastSouthWestResize,
123    IDR_AURA_CURSOR_BIG_NORTH_EAST_SOUTH_WEST_RESIZE, {32, 30}, {64, 60}},
124   {ui::kCursorNorthWestSouthEastResize,
125    IDR_AURA_CURSOR_BIG_NORTH_WEST_SOUTH_EAST_RESIZE, {32, 31}, {64, 62}},
126   {ui::kCursorGrab, IDR_AURA_CURSOR_BIG_GRAB, {21, 11}, {42, 22}},
127   {ui::kCursorGrabbing, IDR_AURA_CURSOR_BIG_GRABBING, {20, 12}, {40, 24}},
128 };
129 
130 const CursorData kAnimatedCursors[] = {
131   {ui::kCursorWait, IDR_THROBBER, {7, 7}, {14, 14}},
132   {ui::kCursorProgress, IDR_THROBBER, {7, 7}, {14, 14}},
133 };
134 
135 const CursorSet kCursorSets[] = {
136   {
137     CURSOR_SET_NORMAL,
138     kNormalCursors, arraysize(kNormalCursors),
139     kAnimatedCursors, arraysize(kAnimatedCursors)
140   },
141   {
142     CURSOR_SET_LARGE,
143     kLargeCursors, arraysize(kLargeCursors),
144     // TODO(yoshiki): Replace animated cursors with big assets. crbug.com/247254
145     kAnimatedCursors, arraysize(kAnimatedCursors)
146   },
147 };
148 
GetCursorSetByType(CursorSetType cursor_set_id)149 const CursorSet* GetCursorSetByType(CursorSetType cursor_set_id) {
150   for (size_t i = 0; i < arraysize(kCursorSets); ++i) {
151     if (kCursorSets[i].id == cursor_set_id)
152       return &kCursorSets[i];
153   }
154 
155   return NULL;
156 }
157 
SearchTable(const CursorData * table,size_t table_length,int id,float scale_factor,int * resource_id,gfx::Point * point)158 bool SearchTable(const CursorData* table,
159                  size_t table_length,
160                  int id,
161                  float scale_factor,
162                  int* resource_id,
163                  gfx::Point* point) {
164   bool resource_2x_available =
165       ResourceBundle::GetSharedInstance().GetMaxScaleFactor() ==
166       SCALE_FACTOR_200P;
167   for (size_t i = 0; i < table_length; ++i) {
168     if (table[i].id == id) {
169       *resource_id = table[i].resource_id;
170       *point = scale_factor == 1.0f || !resource_2x_available ?
171                gfx::Point(table[i].hot_1x.x, table[i].hot_1x.y) :
172                gfx::Point(table[i].hot_2x.x, table[i].hot_2x.y);
173       return true;
174     }
175   }
176 
177   return false;
178 }
179 
180 }  // namespace
181 
GetCursorDataFor(CursorSetType cursor_set_id,int id,float scale_factor,int * resource_id,gfx::Point * point)182 bool GetCursorDataFor(CursorSetType cursor_set_id,
183                       int id,
184                       float scale_factor,
185                       int* resource_id,
186                       gfx::Point* point) {
187   const CursorSet* cursor_set = GetCursorSetByType(cursor_set_id);
188   if (cursor_set &&
189       SearchTable(cursor_set->cursors,
190                   cursor_set->length,
191                   id, scale_factor, resource_id, point)) {
192       return true;
193   }
194 
195   // Falls back to the default cursor set.
196   cursor_set = GetCursorSetByType(ui::CURSOR_SET_NORMAL);
197   DCHECK(cursor_set);
198   return SearchTable(cursor_set->cursors,
199                      cursor_set->length,
200                      id, scale_factor, resource_id, point);
201 }
202 
GetAnimatedCursorDataFor(CursorSetType cursor_set_id,int id,float scale_factor,int * resource_id,gfx::Point * point)203 bool GetAnimatedCursorDataFor(CursorSetType cursor_set_id,
204                               int id,
205                               float scale_factor,
206                               int* resource_id,
207                               gfx::Point* point) {
208   const CursorSet* cursor_set = GetCursorSetByType(cursor_set_id);
209   if (cursor_set &&
210       SearchTable(cursor_set->animated_cursors,
211                   cursor_set->animated_length,
212                   id, scale_factor, resource_id, point)) {
213     return true;
214   }
215 
216   // Falls back to the default cursor set.
217   cursor_set = GetCursorSetByType(ui::CURSOR_SET_NORMAL);
218   DCHECK(cursor_set);
219   return SearchTable(cursor_set->animated_cursors,
220                      cursor_set->animated_length,
221                      id, scale_factor, resource_id, point);
222 }
223 
GetCursorBitmap(const Cursor & cursor,SkBitmap * bitmap,gfx::Point * point)224 bool GetCursorBitmap(const Cursor& cursor,
225                      SkBitmap* bitmap,
226                      gfx::Point* point) {
227   DCHECK(bitmap && point);
228   int resource_id;
229   if (!GetCursorDataFor(ui::CURSOR_SET_NORMAL,
230                         cursor.native_type(),
231                         cursor.device_scale_factor(),
232                         &resource_id,
233                         point)) {
234     return false;
235   }
236 
237   const SkBitmap* cursor_bitmap = ResourceBundle::GetSharedInstance().
238       GetImageSkiaNamed(resource_id)->bitmap();
239   if (!cursor_bitmap)
240     return false;
241   *bitmap = *cursor_bitmap;
242   return true;
243 }
244 
245 }  // namespace ui
246