1// Copyright 2014 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/cursor_util.h"
6
7#include "base/logging.h"
8#include "skia/ext/image_operations.h"
9#include "ui/base/resource/resource_bundle.h"
10#include "ui/gfx/image/image_skia.h"
11#include "ui/gfx/point_conversions.h"
12#include "ui/gfx/size_conversions.h"
13#include "ui/gfx/skbitmap_operations.h"
14#include "ui/gfx/skia_util.h"
15
16namespace ui {
17
18void ScaleAndRotateCursorBitmapAndHotpoint(float scale,
19                                           gfx::Display::Rotation rotation,
20                                           SkBitmap* bitmap,
21                                           gfx::Point* hotpoint) {
22  switch (rotation) {
23    case gfx::Display::ROTATE_0:
24      break;
25    case gfx::Display::ROTATE_90:
26      hotpoint->SetPoint(bitmap->height() - hotpoint->y(), hotpoint->x());
27      *bitmap = SkBitmapOperations::Rotate(
28          *bitmap, SkBitmapOperations::ROTATION_90_CW);
29      break;
30    case gfx::Display::ROTATE_180:
31      hotpoint->SetPoint(
32          bitmap->width() - hotpoint->x(), bitmap->height() - hotpoint->y());
33      *bitmap = SkBitmapOperations::Rotate(
34          *bitmap, SkBitmapOperations::ROTATION_180_CW);
35      break;
36    case gfx::Display::ROTATE_270:
37      hotpoint->SetPoint(hotpoint->y(), bitmap->width() - hotpoint->x());
38      *bitmap = SkBitmapOperations::Rotate(
39          *bitmap, SkBitmapOperations::ROTATION_270_CW);
40      break;
41  }
42
43  if (scale < FLT_EPSILON) {
44    NOTREACHED() << "Scale must be larger than 0.";
45    scale = 1.0f;
46  }
47
48  if (scale == 1.0f)
49    return;
50
51  gfx::Size scaled_size = gfx::ToFlooredSize(
52      gfx::ScaleSize(gfx::Size(bitmap->width(), bitmap->height()), scale));
53
54  *bitmap = skia::ImageOperations::Resize(
55      *bitmap,
56      skia::ImageOperations::RESIZE_BETTER,
57      scaled_size.width(),
58      scaled_size.height());
59  *hotpoint = gfx::ToFlooredPoint(gfx::ScalePoint(*hotpoint, scale));
60}
61
62void GetImageCursorBitmap(int resource_id,
63                          float scale,
64                          gfx::Display::Rotation rotation,
65                          gfx::Point* hotspot,
66                          SkBitmap* bitmap) {
67  const gfx::ImageSkia* image =
68      ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
69  const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale);
70  // TODO(oshima): The cursor should use resource scale factor when
71  // fractional scale factor is enabled. crbug.com/372212
72  (*bitmap) = image_rep.sk_bitmap();
73  ScaleAndRotateCursorBitmapAndHotpoint(
74      scale / image_rep.scale(), rotation, bitmap, hotspot);
75  // |image_rep| is owned by the resource bundle. So we do not need to free it.
76}
77
78void GetAnimatedCursorBitmaps(int resource_id,
79                              float scale,
80                              gfx::Display::Rotation rotation,
81                              gfx::Point* hotspot,
82                              std::vector<SkBitmap>* bitmaps) {
83  // TODO(oshima|tdanderson): Support rotation and fractional scale factor.
84  const gfx::ImageSkia* image =
85      ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
86  const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale);
87  SkBitmap bitmap = image_rep.sk_bitmap();
88  int frame_width = bitmap.height();
89  int frame_height = frame_width;
90  int total_width = bitmap.width();
91  DCHECK_EQ(total_width % frame_width, 0);
92  int frame_count = total_width / frame_width;
93  DCHECK_GT(frame_count, 0);
94
95  bitmaps->resize(frame_count);
96
97  for (int frame = 0; frame < frame_count; ++frame) {
98    int x_offset = frame_width * frame;
99    DCHECK_LE(x_offset + frame_width, total_width);
100
101    SkBitmap cropped = SkBitmapOperations::CreateTiledBitmap(
102        bitmap, x_offset, 0, frame_width, frame_height);
103    DCHECK_EQ(frame_width, cropped.width());
104    DCHECK_EQ(frame_height, cropped.height());
105
106    (*bitmaps)[frame] = cropped;
107  }
108}
109
110}  // namespace ui
111