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/system_ui_resource_manager_impl.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/debug/trace_event.h"
10#include "base/location.h"
11#include "base/observer_list.h"
12#include "base/threading/worker_pool.h"
13#include "cc/resources/ui_resource_bitmap.h"
14#include "content/public/browser/android/ui_resource_client_android.h"
15#include "content/public/browser/android/ui_resource_provider.h"
16#include "third_party/skia/include/core/SkBitmap.h"
17#include "third_party/skia/include/core/SkCanvas.h"
18#include "third_party/skia/include/core/SkPaint.h"
19#include "third_party/skia/include/effects/SkPorterDuff.h"
20#include "ui/gfx/android/java_bitmap.h"
21#include "ui/gfx/screen.h"
22
23namespace content {
24namespace {
25
26SkBitmap CreateOverscrollGlowLBitmap(const gfx::Size& screen_size) {
27  const float kSin = 0.5f;    // sin(PI / 6)
28  const float kCos = 0.866f;  // cos(PI / 6);
29
30  SkPaint paint;
31  paint.setAntiAlias(true);
32  paint.setAlpha(0xBB);
33  paint.setStyle(SkPaint::kFill_Style);
34
35  const float arc_width =
36      std::min(screen_size.width(), screen_size.height()) * 0.5f / kSin;
37  const float y = kCos * arc_width;
38  const float height = arc_width - y;
39  gfx::Size bounds(arc_width, height);
40  SkRect arc_rect = SkRect::MakeXYWH(
41      -arc_width / 2.f, -arc_width - y, arc_width * 2.f, arc_width * 2.f);
42  SkBitmap glow_bitmap;
43  glow_bitmap.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
44  glow_bitmap.eraseColor(SK_ColorTRANSPARENT);
45
46  SkCanvas canvas(glow_bitmap);
47  canvas.clipRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
48  canvas.drawArc(arc_rect, 45, 90, true, paint);
49  return glow_bitmap;
50}
51
52void LoadBitmap(ui::SystemUIResourceManager::ResourceType type,
53                SkBitmap* bitmap_holder,
54                const gfx::Size& screen_size) {
55  TRACE_EVENT1(
56      "browser", "SystemUIResourceManagerImpl::LoadBitmap", "type", type);
57  SkBitmap bitmap;
58  switch (type) {
59    case ui::SystemUIResourceManager::OVERSCROLL_EDGE:
60      bitmap = gfx::CreateSkBitmapFromAndroidResource(
61          "android:drawable/overscroll_edge", gfx::Size(128, 12));
62      break;
63    case ui::SystemUIResourceManager::OVERSCROLL_GLOW:
64      bitmap = gfx::CreateSkBitmapFromAndroidResource(
65          "android:drawable/overscroll_glow", gfx::Size(128, 64));
66      break;
67    case ui::SystemUIResourceManager::OVERSCROLL_GLOW_L:
68      bitmap = CreateOverscrollGlowLBitmap(screen_size);
69      break;
70  }
71  bitmap.setImmutable();
72  *bitmap_holder = bitmap;
73}
74
75}  // namespace
76
77class SystemUIResourceManagerImpl::Entry
78    : public content::UIResourceClientAndroid {
79 public:
80  explicit Entry(UIResourceProvider* provider) : id_(0), provider_(provider) {
81    DCHECK(provider);
82  }
83
84  virtual ~Entry() {
85    if (id_)
86      provider_->DeleteUIResource(id_);
87    id_ = 0;
88  }
89
90  void SetBitmap(const SkBitmap& bitmap) {
91    DCHECK(!bitmap.empty());
92    DCHECK(bitmap_.empty());
93    DCHECK(!id_);
94    bitmap_ = bitmap;
95  }
96
97  cc::UIResourceId GetUIResourceId() {
98    if (bitmap_.empty())
99      return 0;
100    if (!id_)
101      id_ = provider_->CreateUIResource(this);
102    return id_;
103  }
104
105  // content::UIResourceClient implementation.
106  virtual cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
107                                         bool resource_lost) OVERRIDE {
108    DCHECK(!bitmap_.empty());
109    return cc::UIResourceBitmap(bitmap_);
110  }
111
112  // content::UIResourceClientAndroid implementation.
113  virtual void UIResourceIsInvalid() OVERRIDE { id_ = 0; }
114
115  const SkBitmap& bitmap() const { return bitmap_; }
116
117 private:
118  SkBitmap bitmap_;
119  cc::UIResourceId id_;
120  UIResourceProvider* provider_;
121
122  DISALLOW_COPY_AND_ASSIGN(Entry);
123};
124
125SystemUIResourceManagerImpl::SystemUIResourceManagerImpl(
126    UIResourceProvider* ui_resource_provider)
127    : ui_resource_provider_(ui_resource_provider), weak_factory_(this) {
128}
129
130SystemUIResourceManagerImpl::~SystemUIResourceManagerImpl() {
131}
132
133void SystemUIResourceManagerImpl::PreloadResource(ResourceType type) {
134  GetEntry(type);
135}
136
137cc::UIResourceId SystemUIResourceManagerImpl::GetUIResourceId(
138    ResourceType type) {
139  return GetEntry(type)->GetUIResourceId();
140}
141
142SystemUIResourceManagerImpl::Entry* SystemUIResourceManagerImpl::GetEntry(
143    ResourceType type) {
144  DCHECK_GE(type, RESOURCE_TYPE_FIRST);
145  DCHECK_LE(type, RESOURCE_TYPE_LAST);
146  if (!resource_map_[type]) {
147    resource_map_[type].reset(new Entry(ui_resource_provider_));
148    // Lazily build the resource.
149    BuildResource(type);
150  }
151  return resource_map_[type].get();
152}
153
154void SystemUIResourceManagerImpl::BuildResource(ResourceType type) {
155  DCHECK(GetEntry(type)->bitmap().empty());
156
157  // Instead of blocking the main thread, we post a task to load the bitmap.
158  SkBitmap* bitmap = new SkBitmap();
159  gfx::Size screen_size =
160      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
161  base::Closure load_bitmap =
162      base::Bind(&LoadBitmap, type, bitmap, screen_size);
163  base::Closure finished_load =
164      base::Bind(&SystemUIResourceManagerImpl::OnFinishedLoadBitmap,
165                 weak_factory_.GetWeakPtr(),
166                 type,
167                 base::Owned(bitmap));
168  base::WorkerPool::PostTaskAndReply(
169      FROM_HERE, load_bitmap, finished_load, true);
170}
171
172void SystemUIResourceManagerImpl::OnFinishedLoadBitmap(
173    ResourceType type,
174    SkBitmap* bitmap_holder) {
175  DCHECK(bitmap_holder);
176  GetEntry(type)->SetBitmap(*bitmap_holder);
177}
178
179}  // namespace content
180