blob: ea64c80272229acea54c4d26dbf59a2e66842519 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/system_ui_resource_manager_impl.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/observer_list.h"
#include "base/threading/worker_pool.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "content/public/browser/android/ui_resource_client_android.h"
#include "content/public/browser/android/ui_resource_provider.h"
#include "jni/UIResources_jni.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/screen.h"
namespace content {
namespace {
SkBitmap CreateOverscrollGlowLBitmap(const gfx::Size& screen_size) {
const float kSin = 0.5f; // sin(PI / 6)
const float kCos = 0.866f; // cos(PI / 6);
SkPaint paint;
paint.setAntiAlias(true);
paint.setAlpha(0xBB);
paint.setStyle(SkPaint::kFill_Style);
const float arc_width =
std::min(screen_size.width(), screen_size.height()) * 0.5f / kSin;
const float y = kCos * arc_width;
const float height = arc_width - y;
gfx::Size bounds(arc_width, height);
SkRect arc_rect = SkRect::MakeXYWH(
-arc_width / 2.f, -arc_width - y, arc_width * 2.f, arc_width * 2.f);
SkBitmap glow_bitmap;
glow_bitmap.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
glow_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(glow_bitmap);
canvas.clipRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
canvas.drawArc(arc_rect, 45, 90, true, paint);
return glow_bitmap;
}
SkBitmap LoadJavaBitmap(ui::SystemUIResourceType type, const gfx::Size& size) {
ScopedJavaLocalRef<jobject> jobj =
Java_UIResources_getBitmap(base::android::AttachCurrentThread(),
base::android::GetApplicationContext(), type,
size.width(), size.height());
if (jobj.is_null())
return SkBitmap();
SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jobj.obj()));
if (bitmap.isNull())
return bitmap;
if (size.IsEmpty())
return bitmap;
return skia::ImageOperations::Resize(
bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height());
}
void LoadBitmap(ui::SystemUIResourceType type,
SkBitmap* bitmap_holder,
const gfx::Size& screen_size) {
TRACE_EVENT1(
"browser", "SystemUIResourceManagerImpl::LoadBitmap", "type", type);
SkBitmap bitmap;
switch (type) {
case ui::OVERSCROLL_EDGE:
bitmap = LoadJavaBitmap(type, gfx::Size(128, 12));
break;
case ui::OVERSCROLL_GLOW:
bitmap = LoadJavaBitmap(type, gfx::Size(128, 64));
break;
case ui::OVERSCROLL_GLOW_L:
bitmap = CreateOverscrollGlowLBitmap(screen_size);
break;
case ui::OVERSCROLL_REFRESH_IDLE:
case ui::OVERSCROLL_REFRESH_ACTIVE:
bitmap = LoadJavaBitmap(type, gfx::Size());
break;
}
bitmap.setImmutable();
*bitmap_holder = bitmap;
}
} // namespace
class SystemUIResourceManagerImpl::Entry
: public content::UIResourceClientAndroid {
public:
explicit Entry(UIResourceProvider* provider) : id_(0), provider_(provider) {
DCHECK(provider);
}
~Entry() override {
if (id_)
provider_->DeleteUIResource(id_);
id_ = 0;
}
void SetBitmap(const SkBitmap& bitmap) {
DCHECK(!bitmap.empty());
DCHECK(bitmap_.empty());
DCHECK(!id_);
bitmap_ = bitmap;
}
cc::UIResourceId GetUIResourceId() {
if (bitmap_.empty())
return 0;
if (!id_)
id_ = provider_->CreateUIResource(this);
return id_;
}
// content::UIResourceClient implementation.
cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
bool resource_lost) override {
DCHECK(!bitmap_.empty());
return cc::UIResourceBitmap(bitmap_);
}
// content::UIResourceClientAndroid implementation.
void UIResourceIsInvalid() override { id_ = 0; }
const SkBitmap& bitmap() const { return bitmap_; }
private:
SkBitmap bitmap_;
cc::UIResourceId id_;
UIResourceProvider* provider_;
DISALLOW_COPY_AND_ASSIGN(Entry);
};
SystemUIResourceManagerImpl::SystemUIResourceManagerImpl(
UIResourceProvider* ui_resource_provider)
: ui_resource_provider_(ui_resource_provider), weak_factory_(this) {
}
SystemUIResourceManagerImpl::~SystemUIResourceManagerImpl() {
}
void SystemUIResourceManagerImpl::PreloadResource(
ui::SystemUIResourceType type) {
GetEntry(type);
}
cc::UIResourceId SystemUIResourceManagerImpl::GetUIResourceId(
ui::SystemUIResourceType type) {
return GetEntry(type)->GetUIResourceId();
}
SystemUIResourceManagerImpl::Entry* SystemUIResourceManagerImpl::GetEntry(
ui::SystemUIResourceType type) {
DCHECK_GE(type, ui::SYSTEM_UI_RESOURCE_TYPE_FIRST);
DCHECK_LE(type, ui::SYSTEM_UI_RESOURCE_TYPE_LAST);
if (!resource_map_[type]) {
resource_map_[type].reset(new Entry(ui_resource_provider_));
// Lazily build the resource.
BuildResource(type);
}
return resource_map_[type].get();
}
void SystemUIResourceManagerImpl::BuildResource(ui::SystemUIResourceType type) {
DCHECK(GetEntry(type)->bitmap().empty());
// Instead of blocking the main thread, we post a task to load the bitmap.
SkBitmap* bitmap = new SkBitmap();
gfx::Size screen_size =
gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().GetSizeInPixel();
base::Closure load_bitmap =
base::Bind(&LoadBitmap, type, bitmap, screen_size);
base::Closure finished_load =
base::Bind(&SystemUIResourceManagerImpl::OnFinishedLoadBitmap,
weak_factory_.GetWeakPtr(),
type,
base::Owned(bitmap));
base::WorkerPool::PostTaskAndReply(
FROM_HERE, load_bitmap, finished_load, true);
}
void SystemUIResourceManagerImpl::OnFinishedLoadBitmap(
ui::SystemUIResourceType type,
SkBitmap* bitmap_holder) {
DCHECK(bitmap_holder);
GetEntry(type)->SetBitmap(*bitmap_holder);
}
// static
bool SystemUIResourceManagerImpl::RegisterUIResources(JNIEnv* env) {
return RegisterNativesImpl(env);
}
} // namespace content