Home | History | Annotate | Download | only in cursor
      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 "third_party/skia/include/core/SkBitmap.h"
      8 #include "ui/base/resource/resource_bundle.h"
      9 #include "ui/gfx/image/image_skia.h"
     10 #include "ui/gfx/point.h"
     11 #include "ui/resources/grit/ui_resources.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 
    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 
    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 
    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 
    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 
    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