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 "content/browser/android/composited_touch_handle_drawable.h"
6
7#include "base/debug/trace_event.h"
8#include "base/lazy_instance.h"
9#include "base/logging.h"
10#include "cc/layers/ui_resource_layer.h"
11#include "jni/HandleViewResources_jni.h"
12#include "ui/gfx/android/java_bitmap.h"
13
14namespace content {
15
16namespace {
17
18static SkBitmap CreateSkBitmapFromJavaBitmap(
19    base::android::ScopedJavaLocalRef<jobject> jbitmap) {
20  return jbitmap.is_null()
21             ? SkBitmap()
22             : CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jbitmap.obj()));
23}
24
25class HandleResources {
26 public:
27  HandleResources() : loaded_(false) {
28  }
29
30  void LoadIfNecessary(jobject context) {
31    if (loaded_)
32      return;
33
34    loaded_ = true;
35
36    TRACE_EVENT0("browser", "HandleResources::Create");
37    JNIEnv* env = base::android::AttachCurrentThread();
38    if (!context)
39      context = base::android::GetApplicationContext();
40
41    left_bitmap_ = CreateSkBitmapFromJavaBitmap(
42        Java_HandleViewResources_getLeftHandleBitmap(env, context));
43    right_bitmap_ = CreateSkBitmapFromJavaBitmap(
44        Java_HandleViewResources_getRightHandleBitmap(env, context));
45    center_bitmap_ = CreateSkBitmapFromJavaBitmap(
46        Java_HandleViewResources_getCenterHandleBitmap(env, context));
47
48    left_bitmap_.setImmutable();
49    right_bitmap_.setImmutable();
50    center_bitmap_.setImmutable();
51  }
52
53  const SkBitmap& GetBitmap(TouchHandleOrientation orientation) {
54    DCHECK(loaded_);
55    switch (orientation) {
56      case TOUCH_HANDLE_LEFT:
57        return left_bitmap_;
58      case TOUCH_HANDLE_RIGHT:
59        return right_bitmap_;
60      case TOUCH_HANDLE_CENTER:
61        return center_bitmap_;
62      case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
63        NOTREACHED() << "Invalid touch handle orientation.";
64    };
65    return center_bitmap_;
66  }
67
68 private:
69  SkBitmap left_bitmap_;
70  SkBitmap right_bitmap_;
71  SkBitmap center_bitmap_;
72  bool loaded_;
73
74  DISALLOW_COPY_AND_ASSIGN(HandleResources);
75};
76
77base::LazyInstance<HandleResources>::Leaky g_selection_resources;
78
79}  // namespace
80
81CompositedTouchHandleDrawable::CompositedTouchHandleDrawable(
82    cc::Layer* root_layer,
83    float dpi_scale,
84    jobject context)
85    : dpi_scale_(dpi_scale),
86      orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED),
87      layer_(cc::UIResourceLayer::Create()) {
88  g_selection_resources.Get().LoadIfNecessary(context);
89  DCHECK(root_layer);
90  root_layer->AddChild(layer_.get());
91}
92
93CompositedTouchHandleDrawable::~CompositedTouchHandleDrawable() {
94  Detach();
95}
96
97void CompositedTouchHandleDrawable::SetEnabled(bool enabled) {
98  layer_->SetIsDrawable(enabled);
99}
100
101void CompositedTouchHandleDrawable::SetOrientation(
102    TouchHandleOrientation orientation) {
103  DCHECK(layer_->parent());
104  orientation_ = orientation;
105
106  const SkBitmap& bitmap = g_selection_resources.Get().GetBitmap(orientation);
107  layer_->SetBitmap(bitmap);
108  layer_->SetBounds(gfx::Size(bitmap.width(), bitmap.height()));
109
110  switch (orientation_) {
111    case TOUCH_HANDLE_LEFT:
112      focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.75f, 0);
113      break;
114    case TOUCH_HANDLE_RIGHT:
115      focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.25f, 0);
116      break;
117    case TOUCH_HANDLE_CENTER:
118      focal_offset_from_origin_ = gfx::Vector2dF(bitmap.width() * 0.5f, 0);
119      break;
120    case TOUCH_HANDLE_ORIENTATION_UNDEFINED:
121      NOTREACHED() << "Invalid touch handle orientation.";
122      break;
123  };
124
125  layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
126}
127
128void CompositedTouchHandleDrawable::SetAlpha(float alpha) {
129  DCHECK(layer_->parent());
130  layer_->SetOpacity(std::max(0.f, std::min(1.f, alpha)));
131}
132
133void CompositedTouchHandleDrawable::SetFocus(const gfx::PointF& position) {
134  DCHECK(layer_->parent());
135  focal_position_ = gfx::ScalePoint(position, dpi_scale_);
136  layer_->SetPosition(focal_position_ - focal_offset_from_origin_);
137}
138
139void CompositedTouchHandleDrawable::SetVisible(bool visible) {
140  DCHECK(layer_->parent());
141  layer_->SetHideLayerAndSubtree(!visible);
142}
143
144bool CompositedTouchHandleDrawable::IntersectsWith(
145    const gfx::RectF& rect) const {
146  return BoundingRect().Intersects(gfx::ScaleRect(rect, dpi_scale_));
147}
148
149void CompositedTouchHandleDrawable::Detach() {
150  layer_->RemoveFromParent();
151}
152
153gfx::RectF CompositedTouchHandleDrawable::BoundingRect() const {
154  return gfx::RectF(layer_->position().x(),
155                    layer_->position().y(),
156                    layer_->bounds().width(),
157                    layer_->bounds().height());
158}
159
160// static
161bool CompositedTouchHandleDrawable::RegisterHandleViewResources(JNIEnv* env) {
162  return RegisterNativesImpl(env);
163}
164
165}  // namespace content
166