diff options
21 files changed, 602 insertions, 185 deletions
diff --git a/content/browser/android/edge_effect.cc b/content/browser/android/edge_effect.cc index 94e5b51..2979872 100644 --- a/content/browser/android/edge_effect.cc +++ b/content/browser/android/edge_effect.cc @@ -5,6 +5,8 @@ #include "content/browser/android/edge_effect.h" #include "cc/layers/layer.h" +#include "cc/layers/ui_resource_layer.h" +#include "ui/base/android/system_ui_resource_manager.h" namespace content { @@ -118,52 +120,70 @@ gfx::Size ComputeBounds(EdgeEffect::Edge edge, }; } -void DisableLayer(cc::Layer* layer) { - DCHECK(layer); - layer->SetIsDrawable(false); - layer->SetTransform(gfx::Transform()); - layer->SetOpacity(1.f); -} +} // namespace -void UpdateLayer(cc::Layer* layer, - EdgeEffect::Edge edge, - const gfx::SizeF& window_size, - int offset, - int height, - float opacity) { - DCHECK(layer); - layer->SetIsDrawable(true); - gfx::Size bounds = ComputeBounds(edge, window_size, height); - layer->SetTransformOrigin( - gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); - layer->SetTransform(ComputeTransform(edge, window_size, offset, height)); - layer->SetBounds(bounds); - layer->SetOpacity(Clamp(opacity, 0.f, 1.f)); -} +class EdgeEffect::EffectLayer { + public: + EffectLayer(ui::SystemUIResourceManager::ResourceType resource_type, + ui::SystemUIResourceManager* resource_manager) + : ui_resource_layer_(cc::UIResourceLayer::Create()), + resource_type_(resource_type), + resource_manager_(resource_manager) {} + + ~EffectLayer() { ui_resource_layer_->RemoveFromParent(); } + + void SetParent(cc::Layer* parent) { + if (ui_resource_layer_->parent() != parent) + parent->AddChild(ui_resource_layer_); + ui_resource_layer_->SetUIResourceId( + resource_manager_->GetUIResourceId(resource_type_)); + } + + void Disable() { ui_resource_layer_->SetIsDrawable(false); } + + void Update(EdgeEffect::Edge edge, + const gfx::SizeF& window_size, + int offset, + int height, + float opacity) { + ui_resource_layer_->SetUIResourceId( + resource_manager_->GetUIResourceId(resource_type_)); + ui_resource_layer_->SetIsDrawable(true); + gfx::Size bounds = ComputeBounds(edge, window_size, height); + ui_resource_layer_->SetTransformOrigin( + gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0)); + ui_resource_layer_->SetTransform( + ComputeTransform(edge, window_size, offset, height)); + ui_resource_layer_->SetBounds(bounds); + ui_resource_layer_->SetOpacity(Clamp(opacity, 0.f, 1.f)); + } -} // namespace - -EdgeEffect::EdgeEffect(scoped_refptr<cc::Layer> edge, - scoped_refptr<cc::Layer> glow) - : edge_(edge) - , glow_(glow) - , edge_alpha_(0) - , edge_scale_y_(0) - , glow_alpha_(0) - , glow_scale_y_(0) - , edge_alpha_start_(0) - , edge_alpha_finish_(0) - , edge_scale_y_start_(0) - , edge_scale_y_finish_(0) - , glow_alpha_start_(0) - , glow_alpha_finish_(0) - , glow_scale_y_start_(0) - , glow_scale_y_finish_(0) - , state_(STATE_IDLE) - , pull_distance_(0) { - // Prevent the provided layers from drawing until the effect is activated. - DisableLayer(edge_.get()); - DisableLayer(glow_.get()); + scoped_refptr<cc::UIResourceLayer> ui_resource_layer_; + ui::SystemUIResourceManager::ResourceType resource_type_; + ui::SystemUIResourceManager* resource_manager_; + + DISALLOW_COPY_AND_ASSIGN(EffectLayer); +}; + +EdgeEffect::EdgeEffect(ui::SystemUIResourceManager* resource_manager) + : edge_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_EDGE, + resource_manager)), + glow_(new EffectLayer(ui::SystemUIResourceManager::OVERSCROLL_GLOW, + resource_manager)), + edge_alpha_(0), + edge_scale_y_(0), + glow_alpha_(0), + glow_scale_y_(0), + edge_alpha_start_(0), + edge_alpha_finish_(0), + edge_scale_y_start_(0), + edge_scale_y_finish_(0), + glow_alpha_start_(0), + glow_alpha_finish_(0), + glow_scale_y_start_(0), + glow_scale_y_finish_(0), + state_(STATE_IDLE), + pull_distance_(0) { } EdgeEffect::~EdgeEffect() { } @@ -173,8 +193,8 @@ bool EdgeEffect::IsFinished() const { } void EdgeEffect::Finish() { - DisableLayer(edge_.get()); - DisableLayer(glow_.get()); + edge_->Disable(); + glow_->Disable(); pull_distance_ = 0; state_ = STATE_IDLE; } @@ -359,8 +379,8 @@ void EdgeEffect::ApplyToLayers(gfx::SizeF window_size, // An empty window size, while meaningless, is also relatively harmless, and // will simply prevent any drawing of the layers. if (window_size.IsEmpty()) { - DisableLayer(edge_.get()); - DisableLayer(glow_.get()); + edge_->Disable(); + glow_->Disable(); return; } @@ -368,13 +388,26 @@ void EdgeEffect::ApplyToLayers(gfx::SizeF window_size, const int scaled_glow_height = static_cast<int>( std::min(glow_height * glow_scale_y_ * kGlowHeightToWidthRatio * 0.6f, glow_height * kMaxGlowHeight) + 0.5f); - UpdateLayer( - glow_.get(), edge, window_size, offset, scaled_glow_height, glow_alpha_); + glow_->Update(edge, window_size, offset, scaled_glow_height, glow_alpha_); // Edge - const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_); - UpdateLayer( - edge_.get(), edge, window_size, offset, scaled_edge_height, edge_alpha_); + const int scaled_edge_height = static_cast<int>(edge_height * edge_scale_y_); + edge_->Update(edge, window_size, offset, scaled_edge_height, edge_alpha_); +} + +void EdgeEffect::SetParent(cc::Layer* parent) { + edge_->SetParent(parent); + glow_->SetParent(parent); +} + +// static +void EdgeEffect::PreloadResources( + ui::SystemUIResourceManager* resource_manager) { + DCHECK(resource_manager); + resource_manager->PreloadResource( + ui::SystemUIResourceManager::OVERSCROLL_EDGE); + resource_manager->PreloadResource( + ui::SystemUIResourceManager::OVERSCROLL_GLOW); } } // namespace content diff --git a/content/browser/android/edge_effect.h b/content/browser/android/edge_effect.h index b8febba..a8f944c 100644 --- a/content/browser/android/edge_effect.h +++ b/content/browser/android/edge_effect.h @@ -6,7 +6,7 @@ #define CONTENT_BROWSER_ANDROID_EDGE_EFFECT_H_ #include "base/basictypes.h" -#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "ui/gfx/size_f.h" @@ -14,6 +14,10 @@ namespace cc { class Layer; } +namespace ui { +class SystemUIResourceManager; +} + namespace content { /* |EdgeEffect| mirrors its Android counterpart, EdgeEffect.java. @@ -24,7 +28,7 @@ namespace content { * All coordinates and dimensions are in device pixels. */ class EdgeEffect { -public: + public: enum Edge { EDGE_TOP = 0, EDGE_LEFT, @@ -33,7 +37,7 @@ public: EDGE_COUNT }; - EdgeEffect(scoped_refptr<cc::Layer> edge, scoped_refptr<cc::Layer> glow); + explicit EdgeEffect(ui::SystemUIResourceManager* resource_manager); ~EdgeEffect(); void Pull(base::TimeTicks current_time, float delta_distance); @@ -50,8 +54,11 @@ public: float glow_height, float offset); -private: + void SetParent(cc::Layer* parent); + + static void PreloadResources(ui::SystemUIResourceManager* resource_manager); + private: enum State { STATE_IDLE = 0, STATE_PULL, @@ -60,8 +67,9 @@ private: STATE_PULL_DECAY }; - scoped_refptr<cc::Layer> edge_; - scoped_refptr<cc::Layer> glow_; + class EffectLayer; + scoped_ptr<EffectLayer> edge_; + scoped_ptr<EffectLayer> glow_; float edge_alpha_; float edge_scale_y_; diff --git a/content/browser/android/overscroll_glow.cc b/content/browser/android/overscroll_glow.cc index fb491f3..3f316d8 100644 --- a/content/browser/android/overscroll_glow.cc +++ b/content/browser/android/overscroll_glow.cc @@ -6,11 +6,8 @@ #include "base/debug/trace_event.h" #include "base/lazy_instance.h" -#include "base/threading/worker_pool.h" -#include "cc/layers/image_layer.h" +#include "cc/layers/layer.h" #include "content/browser/android/edge_effect.h" -#include "skia/ext/image_operations.h" -#include "ui/gfx/android/java_bitmap.h" using std::max; using std::min; @@ -20,57 +17,9 @@ namespace content { namespace { const float kEpsilon = 1e-3f; -const int kScaledEdgeHeight = 12; -const int kScaledGlowHeight = 64; const float kEdgeHeightAtMdpi = 12.f; const float kGlowHeightAtMdpi = 128.f; -SkBitmap CreateSkBitmapFromAndroidResource(const char* name, gfx::Size size) { - base::android::ScopedJavaLocalRef<jobject> jobj = - gfx::CreateJavaBitmapFromAndroidResource(name, size); - if (jobj.is_null()) - return SkBitmap(); - - SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jobj.obj())); - if (bitmap.isNull()) - return bitmap; - - return skia::ImageOperations::Resize( - bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height()); -} - -class OverscrollResources { - public: - OverscrollResources() { - TRACE_EVENT0("browser", "OverscrollResources::Create"); - edge_bitmap_ = - CreateSkBitmapFromAndroidResource("android:drawable/overscroll_edge", - gfx::Size(128, kScaledEdgeHeight)); - glow_bitmap_ = - CreateSkBitmapFromAndroidResource("android:drawable/overscroll_glow", - gfx::Size(128, kScaledGlowHeight)); - } - - const SkBitmap& edge_bitmap() const { return edge_bitmap_; } - const SkBitmap& glow_bitmap() const { return glow_bitmap_; } - - private: - SkBitmap edge_bitmap_; - SkBitmap glow_bitmap_; - - DISALLOW_COPY_AND_ASSIGN(OverscrollResources); -}; - -// Leaky to allow access from a worker thread. -base::LazyInstance<OverscrollResources>::Leaky g_overscroll_resources = - LAZY_INSTANCE_INITIALIZER; - -scoped_refptr<cc::Layer> CreateImageLayer(const SkBitmap& bitmap) { - scoped_refptr<cc::ImageLayer> layer = cc::ImageLayer::Create(); - layer->SetBitmap(bitmap); - return layer; -} - bool IsApproxZero(float value) { return std::abs(value) < kEpsilon; } @@ -83,25 +32,18 @@ gfx::Vector2dF ZeroSmallComponents(gfx::Vector2dF vector) { return vector; } -// Force loading of any necessary resources. This function is thread-safe. -void EnsureResources() { - g_overscroll_resources.Get(); -} - -} // namespace - -scoped_ptr<OverscrollGlow> OverscrollGlow::Create(bool enabled) { - // Don't block the main thread with effect resource loading during creation. - // Effect instantiation is deferred until the effect overscrolls, in which - // case the main thread may block until the resource has loaded. - if (enabled && g_overscroll_resources == NULL) - base::WorkerPool::PostTask(FROM_HERE, base::Bind(EnsureResources), true); +} // namespace - return make_scoped_ptr(new OverscrollGlow(enabled)); +scoped_ptr<OverscrollGlow> OverscrollGlow::Create( + ui::SystemUIResourceManager* resource_manager) { + return make_scoped_ptr(new OverscrollGlow(resource_manager)); } -OverscrollGlow::OverscrollGlow(bool enabled) - : enabled_(enabled), initialized_(false) {} +OverscrollGlow::OverscrollGlow(ui::SystemUIResourceManager* resource_manager) + : enabled_(true), initialized_(false), resource_manager_(resource_manager) { + DCHECK(resource_manager_); + EdgeEffect::PreloadResources(resource_manager_); +} OverscrollGlow::~OverscrollGlow() { Detach(); @@ -222,6 +164,9 @@ void OverscrollGlow::UpdateLayerAttachment(cc::Layer* parent) { if (root_layer_->parent() != parent) parent->AddChild(root_layer_); + + for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) + edge_effects_[i]->SetParent(root_layer_); } void OverscrollGlow::Detach() { @@ -234,22 +179,10 @@ bool OverscrollGlow::InitializeIfNecessary() { if (initialized_) return true; - const SkBitmap& edge = g_overscroll_resources.Get().edge_bitmap(); - const SkBitmap& glow = g_overscroll_resources.Get().glow_bitmap(); - if (edge.isNull() || glow.isNull()) { - Disable(); - return false; - } - DCHECK(!root_layer_); root_layer_ = cc::Layer::Create(); - for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) { - scoped_refptr<cc::Layer> edge_layer = CreateImageLayer(edge); - scoped_refptr<cc::Layer> glow_layer = CreateImageLayer(glow); - root_layer_->AddChild(edge_layer); - root_layer_->AddChild(glow_layer); - edge_effects_[i] = make_scoped_ptr(new EdgeEffect(edge_layer, glow_layer)); - } + for (size_t i = 0; i < EdgeEffect::EDGE_COUNT; ++i) + edge_effects_[i] = make_scoped_ptr(new EdgeEffect(resource_manager_)); initialized_ = true; return true; diff --git a/content/browser/android/overscroll_glow.h b/content/browser/android/overscroll_glow.h index 0a555d4..7500940 100644 --- a/content/browser/android/overscroll_glow.h +++ b/content/browser/android/overscroll_glow.h @@ -14,8 +14,8 @@ class SkBitmap; -namespace cc { -class Layer; +namespace ui { +class SystemUIResourceManager; } namespace content { @@ -26,11 +26,11 @@ namespace content { */ class OverscrollGlow { public: - // Create a new effect. If |enabled| is false, the effect will remain - // deactivated until explicitly enabled. - // Note: No resources will be allocated until the effect is both - // enabled and an overscroll event has occurred. - static scoped_ptr<OverscrollGlow> Create(bool enabled); + // Create a new effect. |resource_manager| provides the resource for the + // effect. |resource_manager| must outlive the effect. The effect is + // activated by default. + static scoped_ptr<OverscrollGlow> Create( + ui::SystemUIResourceManager* resource_manager); ~OverscrollGlow(); @@ -70,7 +70,7 @@ class OverscrollGlow { private: enum Axis { AXIS_X, AXIS_Y }; - OverscrollGlow(bool enabled); + explicit OverscrollGlow(ui::SystemUIResourceManager* resource_manager); // Returns whether the effect is initialized. bool InitializeIfNecessary(); @@ -94,6 +94,7 @@ class OverscrollGlow { bool initialized_; scoped_refptr<cc::Layer> root_layer_; + ui::SystemUIResourceManager* resource_manager_; DISALLOW_COPY_AND_ASSIGN(OverscrollGlow); }; diff --git a/content/browser/android/system_ui_resource_manager_impl.cc b/content/browser/android/system_ui_resource_manager_impl.cc new file mode 100644 index 0000000..6da221b --- /dev/null +++ b/content/browser/android/system_ui_resource_manager_impl.cc @@ -0,0 +1,137 @@ +// 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/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 "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/android/java_bitmap.h" + +namespace content { + +class SystemUIResourceManagerImpl::Entry + : public content::UIResourceClientAndroid { + public: + explicit Entry(UIResourceProvider* provider) : id_(0), provider_(provider) { + DCHECK(provider); + } + + virtual ~Entry() { + 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. + virtual cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid, + bool resource_lost) OVERRIDE { + DCHECK(!bitmap_.empty()); + return cc::UIResourceBitmap(bitmap_); + } + + // content::UIResourceClientAndroid implementation. + virtual 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(ResourceType type) { + GetEntry(type); +} + +cc::UIResourceId SystemUIResourceManagerImpl::GetUIResourceId( + ResourceType type) { + return GetEntry(type)->GetUIResourceId(); +} + +SystemUIResourceManagerImpl::Entry* SystemUIResourceManagerImpl::GetEntry( + ResourceType type) { + DCHECK_GE(type, RESOURCE_TYPE_FIRST); + DCHECK_LE(type, 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(ResourceType type) { + DCHECK(GetEntry(type)->bitmap().empty()); + + // Instead of blocking the main thread, we post a task to load the bitmap. + SkBitmap* bitmap = new SkBitmap(); + base::Closure load_bitmap = + base::Bind(&SystemUIResourceManagerImpl::LoadBitmap, type, bitmap); + 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::LoadBitmap(ResourceType type, + SkBitmap* bitmap_holder) { + SkBitmap bitmap; + switch (type) { + case ui::SystemUIResourceManager::OVERSCROLL_EDGE: + bitmap = gfx::CreateSkBitmapFromAndroidResource( + "android:drawable/overscroll_edge", gfx::Size(128, 12)); + break; + case ui::SystemUIResourceManager::OVERSCROLL_GLOW: + bitmap = gfx::CreateSkBitmapFromAndroidResource( + "android:drawable/overscroll_glow", gfx::Size(128, 64)); + break; + } + bitmap.setImmutable(); + *bitmap_holder = bitmap; +} + +void SystemUIResourceManagerImpl::OnFinishedLoadBitmap( + ResourceType type, + SkBitmap* bitmap_holder) { + DCHECK(bitmap_holder); + GetEntry(type)->SetBitmap(*bitmap_holder); +} + +} // namespace content diff --git a/content/browser/android/system_ui_resource_manager_impl.h b/content/browser/android/system_ui_resource_manager_impl.h new file mode 100644 index 0000000..c5792a1 --- /dev/null +++ b/content/browser/android/system_ui_resource_manager_impl.h @@ -0,0 +1,55 @@ +// 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. + +#ifndef CONTENT_BROWSER_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_ +#define CONTENT_BROWSER_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_ + +#include "base/basictypes.h" +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" +#include "ui/base/android/system_ui_resource_manager.h" + +class SkBitmap; + +namespace cc { +class UIResourceBitmap; +} + +namespace content { + +class UIResourceProvider; + +class CONTENT_EXPORT SystemUIResourceManagerImpl + : public ui::SystemUIResourceManager { + public: + explicit SystemUIResourceManagerImpl( + UIResourceProvider* ui_resource_provider); + virtual ~SystemUIResourceManagerImpl(); + + virtual void PreloadResource(ResourceType type) OVERRIDE; + virtual cc::UIResourceId GetUIResourceId(ResourceType type) OVERRIDE; + + private: + friend class TestSystemUIResourceManagerImpl; + class Entry; + + // Start loading the resource bitmap. virtual for testing. + virtual void BuildResource(ResourceType type); + + Entry* GetEntry(ResourceType type); + static void LoadBitmap(ResourceType, SkBitmap* bitmap_holder); + void OnFinishedLoadBitmap(ResourceType, SkBitmap* bitmap_holder); + + scoped_ptr<Entry> resource_map_[RESOURCE_TYPE_LAST + 1]; + UIResourceProvider* ui_resource_provider_; + + base::WeakPtrFactory<SystemUIResourceManagerImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SystemUIResourceManagerImpl); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_IMPL_H_ diff --git a/content/browser/android/system_ui_resource_manager_impl_unittest.cc b/content/browser/android/system_ui_resource_manager_impl_unittest.cc new file mode 100644 index 0000000..95a7e9b --- /dev/null +++ b/content/browser/android/system_ui_resource_manager_impl_unittest.cc @@ -0,0 +1,167 @@ +// 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 "cc/resources/ui_resource_bitmap.h" +#include "content/browser/android/system_ui_resource_manager_impl.h" +#include "content/public/browser/android/ui_resource_client_android.h" +#include "content/public/browser/android/ui_resource_provider.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" + +namespace content { + +class TestSystemUIResourceManagerImpl + : public content::SystemUIResourceManagerImpl { + public: + TestSystemUIResourceManagerImpl(content::UIResourceProvider* provider) + : SystemUIResourceManagerImpl(provider) {} + + virtual ~TestSystemUIResourceManagerImpl() {} + + virtual void BuildResource( + ui::SystemUIResourceManager::ResourceType type) OVERRIDE {} + + void SetResourceAsLoaded(ui::SystemUIResourceManager::ResourceType type) { + SkBitmap small_bitmap; + SkCanvas canvas(small_bitmap); + small_bitmap.allocPixels( + SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType)); + canvas.drawColor(SK_ColorWHITE); + small_bitmap.setImmutable(); + OnFinishedLoadBitmap(type, &small_bitmap); + } +}; + +namespace { + +const ui::SystemUIResourceManager::ResourceType TEST_RESOURCE_TYPE = + ui::SystemUIResourceManager::OVERSCROLL_GLOW; + +class MockUIResourceProvider : public content::UIResourceProvider { + public: + MockUIResourceProvider() + : next_ui_resource_id_(1), + has_layer_tree_host_(true), + system_ui_resource_manager_(this) {} + + virtual ~MockUIResourceProvider() {} + + virtual cc::UIResourceId CreateUIResource( + content::UIResourceClientAndroid* client) OVERRIDE { + if (!has_layer_tree_host_) + return 0; + cc::UIResourceId id = next_ui_resource_id_++; + client->GetBitmap(id, false); + ui_resource_client_map_[id] = client; + return id; + } + + virtual void DeleteUIResource(cc::UIResourceId id) OVERRIDE { + CHECK(has_layer_tree_host_); + ui_resource_client_map_.erase(id); + } + + void LayerTreeHostCleared() { + has_layer_tree_host_ = false; + UIResourceClientMap client_map = ui_resource_client_map_; + ui_resource_client_map_.clear(); + for (UIResourceClientMap::iterator iter = client_map.begin(); + iter != client_map.end(); + iter++) { + iter->second->UIResourceIsInvalid(); + } + } + + void LayerTreeHostReturned() { has_layer_tree_host_ = true; } + + TestSystemUIResourceManagerImpl& GetSystemUIResourceManager() { + return system_ui_resource_manager_; + } + + cc::UIResourceId next_ui_resource_id() const { return next_ui_resource_id_; } + + private: + typedef base::hash_map<cc::UIResourceId, content::UIResourceClientAndroid*> + UIResourceClientMap; + + cc::UIResourceId next_ui_resource_id_; + UIResourceClientMap ui_resource_client_map_; + bool has_layer_tree_host_; + + // The UIResourceProvider owns the SystemUIResourceManager. + TestSystemUIResourceManagerImpl system_ui_resource_manager_; +}; + +} // namespace + +class SystemUIResourceManagerImplTest : public testing::Test { + public: + void PreloadResource(ui::SystemUIResourceManager::ResourceType type) { + ui_resource_provider_.GetSystemUIResourceManager().PreloadResource(type); + } + + cc::UIResourceId GetUIResourceId( + ui::SystemUIResourceManager::ResourceType type) { + return ui_resource_provider_.GetSystemUIResourceManager().GetUIResourceId( + type); + } + + void LayerTreeHostCleared() { ui_resource_provider_.LayerTreeHostCleared(); } + + void LayerTreeHostReturned() { + ui_resource_provider_.LayerTreeHostReturned(); + } + + void SetResourceAsLoaded(ui::SystemUIResourceManager::ResourceType type) { + ui_resource_provider_.GetSystemUIResourceManager().SetResourceAsLoaded( + type); + } + + cc::UIResourceId GetNextUIResourceId() const { + return ui_resource_provider_.next_ui_resource_id(); + } + + private: + MockUIResourceProvider ui_resource_provider_; +}; + +TEST_F(SystemUIResourceManagerImplTest, GetResourceAfterBitmapLoaded) { + SetResourceAsLoaded(TEST_RESOURCE_TYPE); + EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE)); +} + +TEST_F(SystemUIResourceManagerImplTest, GetResourceBeforeLoadBitmap) { + EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + SetResourceAsLoaded(TEST_RESOURCE_TYPE); + EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE)); +} + +TEST_F(SystemUIResourceManagerImplTest, PreloadEnsureResource) { + // Preloading the resource should trigger bitmap loading, but the actual + // resource id will not be generated until it is explicitly requested. + cc::UIResourceId first_resource_id = GetNextUIResourceId(); + PreloadResource(TEST_RESOURCE_TYPE); + SetResourceAsLoaded(TEST_RESOURCE_TYPE); + EXPECT_EQ(first_resource_id, GetNextUIResourceId()); + EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + EXPECT_NE(first_resource_id, GetNextUIResourceId()); +} + +TEST_F(SystemUIResourceManagerImplTest, ResetLayerTreeHost) { + EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + LayerTreeHostCleared(); + EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + LayerTreeHostReturned(); + EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + + SetResourceAsLoaded(TEST_RESOURCE_TYPE); + EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + LayerTreeHostCleared(); + EXPECT_EQ(0, GetUIResourceId(TEST_RESOURCE_TYPE)); + LayerTreeHostReturned(); + EXPECT_NE(0, GetUIResourceId(TEST_RESOURCE_TYPE)); +} + +} // namespace content diff --git a/content/browser/android/ui_resource_provider_impl.cc b/content/browser/android/ui_resource_provider_impl.cc index f97975c..d26d42f 100644 --- a/content/browser/android/ui_resource_provider_impl.cc +++ b/content/browser/android/ui_resource_provider_impl.cc @@ -10,7 +10,8 @@ namespace content { -UIResourceProviderImpl::UIResourceProviderImpl() : host_(NULL) { +UIResourceProviderImpl::UIResourceProviderImpl() + : system_ui_resource_manager_(this), host_(NULL) { } UIResourceProviderImpl::~UIResourceProviderImpl() { @@ -57,4 +58,9 @@ void UIResourceProviderImpl::DeleteUIResource(cc::UIResourceId ui_resource_id) { host_->DeleteUIResource(ui_resource_id); } +ui::SystemUIResourceManager& +UIResourceProviderImpl::GetSystemUIResourceManager() { + return system_ui_resource_manager_; +} + } // namespace content diff --git a/content/browser/android/ui_resource_provider_impl.h b/content/browser/android/ui_resource_provider_impl.h index 79c2301..57c9ab8 100644 --- a/content/browser/android/ui_resource_provider_impl.h +++ b/content/browser/android/ui_resource_provider_impl.h @@ -6,6 +6,7 @@ #define CONTENT_BROWSER_ANDROID_UI_RESOURCE_PROVIDER_IMPL_H_ #include "base/containers/hash_tables.h" +#include "content/browser/android/system_ui_resource_manager_impl.h" #include "content/public/browser/android/ui_resource_provider.h" namespace cc { @@ -31,11 +32,13 @@ class UIResourceProviderImpl : public UIResourceProvider { virtual void DeleteUIResource(cc::UIResourceId resource_id) OVERRIDE; + ui::SystemUIResourceManager& GetSystemUIResourceManager(); + private: typedef base::hash_map<cc::UIResourceId, UIResourceClientAndroid*> UIResourceClientMap; UIResourceClientMap ui_resource_client_map_; - + SystemUIResourceManagerImpl system_ui_resource_manager_; cc::LayerTreeHost* host_; DISALLOW_COPY_AND_ASSIGN(UIResourceProviderImpl); diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 70ebbfe..d704f28 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -340,6 +340,10 @@ UIResourceProvider& CompositorImpl::GetUIResourceProvider() { return ui_resource_provider_; } +ui::SystemUIResourceManager& CompositorImpl::GetSystemUIResourceManager() { + return ui_resource_provider_.GetSystemUIResourceManager(); +} + void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { if (subroot_layer_) { subroot_layer_->RemoveFromParent(); diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 4792d90..9b75bd9 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -8,10 +8,8 @@ #include "base/basictypes.h" #include "base/cancelable_callback.h" #include "base/compiler_specific.h" -#include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "cc/resources/ui_resource_client.h" #include "cc/trees/layer_tree_host_client.h" #include "cc/trees/layer_tree_host_single_thread_client.h" #include "content/browser/android/ui_resource_provider_impl.h" @@ -19,6 +17,7 @@ #include "content/common/content_export.h" #include "content/public/browser/android/compositor.h" #include "third_party/khronos/GLES2/gl2.h" +#include "ui/base/android/system_ui_resource_manager.h" #include "ui/base/android/window_android_compositor.h" class SkBitmap; @@ -98,6 +97,7 @@ class CONTENT_EXPORT CompositorImpl virtual void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) OVERRIDE; virtual void SetNeedsAnimate() OVERRIDE; + virtual ui::SystemUIResourceManager& GetSystemUIResourceManager() OVERRIDE; enum CompositingTrigger { DO_NOT_COMPOSITE, @@ -127,9 +127,6 @@ class CONTENT_EXPORT CompositorImpl composite_on_vsync_trigger_ = DO_NOT_COMPOSITE; will_composite_immediately_ = false; } - cc::UIResourceId GenerateUIResourceFromUIResourceBitmap( - const cc::UIResourceBitmap& bitmap, - bool is_transient); void OnGpuChannelEstablished(); // root_layer_ is the persistent internal root layer, while subroot_layer_ diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index e43f452..c52e845 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc @@ -192,7 +192,6 @@ RenderWidgetHostViewAndroid::RenderWidgetHostViewAndroid( weak_ptr_factory_(this), overscroll_effect_enabled_(!CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableOverscrollEdgeEffect)), - overscroll_effect_(OverscrollGlow::Create(overscroll_effect_enabled_)), gesture_provider_(CreateGestureProviderConfig(), this), gesture_text_selector_(this), touch_scrolling_(false), @@ -368,7 +367,7 @@ void RenderWidgetHostViewAndroid::MovePluginWindows( void RenderWidgetHostViewAndroid::Focus() { host_->Focus(); host_->SetInputMethodActive(true); - if (overscroll_effect_enabled_) + if (overscroll_effect_) overscroll_effect_->Enable(); } @@ -376,7 +375,8 @@ void RenderWidgetHostViewAndroid::Blur() { host_->ExecuteEditCommand("Unselect", ""); host_->SetInputMethodActive(false); host_->Blur(); - overscroll_effect_->Disable(); + if (overscroll_effect_) + overscroll_effect_->Disable(); } bool RenderWidgetHostViewAndroid::HasFocus() const { @@ -929,8 +929,10 @@ void RenderWidgetHostViewAndroid::ComputeContentsSize( gfx::Size(texture_size_in_layer_.width() - offset.x(), texture_size_in_layer_.height() - offset.y()); - overscroll_effect_->UpdateDisplayParameters( - CreateOverscrollDisplayParameters(frame_metadata)); + if (overscroll_effect_) { + overscroll_effect_->UpdateDisplayParameters( + CreateOverscrollDisplayParameters(frame_metadata)); + } } void RenderWidgetHostViewAndroid::InternalSwapCompositorFrame( @@ -1143,7 +1145,7 @@ void RenderWidgetHostViewAndroid::AttachLayers() { return; content_view_core_->AttachLayer(layer_); - if (overscroll_effect_enabled_) + if (overscroll_effect_) overscroll_effect_->Enable(); layer_->SetHideLayerAndSubtree(!is_showing_); } @@ -1156,11 +1158,13 @@ void RenderWidgetHostViewAndroid::RemoveLayers() { return; content_view_core_->RemoveLayer(layer_); - overscroll_effect_->Disable(); + if (overscroll_effect_) + overscroll_effect_->Disable(); } bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) { - bool needs_animate = overscroll_effect_->Animate(frame_time); + bool needs_animate = + overscroll_effect_ ? overscroll_effect_->Animate(frame_time) : false; if (selection_controller_) needs_animate |= selection_controller_->Animate(frame_time); return needs_animate; @@ -1361,8 +1365,8 @@ void RenderWidgetHostViewAndroid::SendMouseWheelEvent( void RenderWidgetHostViewAndroid::SendGestureEvent( const blink::WebGestureEvent& event) { // Sending a gesture that may trigger overscroll should resume the effect. - if (overscroll_effect_enabled_) - overscroll_effect_->Enable(); + if (overscroll_effect_) + overscroll_effect_->Enable(); if (host_) host_->ForwardGestureEventWithLatencyInfo(event, CreateLatencyInfo(event)); @@ -1408,7 +1412,9 @@ void RenderWidgetHostViewAndroid::DidOverscroll( return; const float device_scale_factor = content_view_core_->GetDpiScale(); - if (overscroll_effect_->OnOverscrolled( + + if (overscroll_effect_ && + overscroll_effect_->OnOverscrolled( content_view_core_->GetLayer(), base::TimeTicks::Now(), gfx::ScaleVector2d(params.accumulated_overscroll, @@ -1475,6 +1481,16 @@ void RenderWidgetHostViewAndroid::SetContentViewCore( if (!selection_controller_) selection_controller_.reset(new TouchSelectionController(this)); + + if (!content_view_core_) { + overscroll_effect_.reset(); + } else if (overscroll_effect_enabled_ && !overscroll_effect_) { + DCHECK(content_view_core_->GetWindowAndroid()->GetCompositor()); + overscroll_effect_ = + OverscrollGlow::Create(&content_view_core_->GetWindowAndroid() + ->GetCompositor() + ->GetSystemUIResourceManager()); + } } void RenderWidgetHostViewAndroid::RunAckCallbacks() { diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index e52652a..91f9d48 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h @@ -355,7 +355,6 @@ class CONTENT_EXPORT RenderWidgetHostViewAndroid const bool overscroll_effect_enabled_; // Used to render overscroll overlays. - // Note: |overscroll_effect_| will never be NULL, even if it's never enabled. scoped_ptr<OverscrollGlow> overscroll_effect_; // Provides gesture synthesis given a stream of touch events (derived from diff --git a/content/content_browser.gypi b/content/content_browser.gypi index bd2476f..46b7ca7 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -313,6 +313,8 @@ 'browser/android/popup_touch_handle_drawable.h', 'browser/android/surface_texture_peer_browser_impl.cc', 'browser/android/surface_texture_peer_browser_impl.h', + 'browser/android/system_ui_resource_manager_impl.cc', + 'browser/android/system_ui_resource_manager_impl.h', 'browser/android/tracing_controller_android.cc', 'browser/android/tracing_controller_android.h', 'browser/android/web_contents_observer_android.cc', diff --git a/content/content_tests.gypi b/content/content_tests.gypi index b15c5d7..f7a3c38 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -901,6 +901,7 @@ 'browser/android/java/gin_java_method_invocation_helper_unittest.cc', 'browser/android/java/java_type_unittest.cc', 'browser/android/java/jni_helper_unittest.cc', + 'browser/android/system_ui_resource_manager_impl_unittest.cc', 'renderer/java/gin_java_bridge_value_converter_unittest.cc', ], 'sources!': [ diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index ddadf1b..76dcaa4 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn @@ -21,6 +21,7 @@ component("base") { "accelerators/platform_accelerator.h", "accelerators/platform_accelerator_cocoa.h", "accelerators/platform_accelerator_cocoa.mm", + "android/system_ui_resource_manager.h", "android/ui_base_jni_registrar.cc", "android/ui_base_jni_registrar.h", "android/view_android.cc", diff --git a/ui/base/android/system_ui_resource_manager.h b/ui/base/android/system_ui_resource_manager.h new file mode 100644 index 0000000..03a112d --- /dev/null +++ b/ui/base/android/system_ui_resource_manager.h @@ -0,0 +1,41 @@ +// 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. + +#ifndef UI_BASE_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_H_ +#define UI_BASE_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_H_ + +#include "cc/resources/ui_resource_client.h" +#include "ui/base/ui_base_export.h" + +namespace ui { + +// Interface for loading and accessing shared system UI resources. +class UI_BASE_EXPORT SystemUIResourceManager { + public: + enum ResourceType { + OVERSCROLL_EDGE = 0, + OVERSCROLL_GLOW, + RESOURCE_TYPE_FIRST = OVERSCROLL_EDGE, + RESOURCE_TYPE_LAST = OVERSCROLL_GLOW + }; + + virtual ~SystemUIResourceManager() {} + + // Optionally trigger bitmap loading for a given |resource|, if necessary. + // Note that this operation may be asynchronous, and subsequent queries to + // |GetUIResourceId()| will yield a valid result only after loading finishes. + // This method is particularly useful for idly loading a resource before an + // explicit cc::UIResourceId is required. Repeated calls will be ignored. + virtual void PreloadResource(ResourceType resource) = 0; + + // Return the resource id associated with |resource|. If loading hasn't yet + // begun for the given |resource|, it will be triggered immediately. If + // loading is asynchronous, 0 will be returned until loading has finished, and + // the caller is responsible for re-querying until a valid id is returned. + virtual cc::UIResourceId GetUIResourceId(ResourceType resource) = 0; +}; + +} // namespace ui + +#endif // UI_BASE_ANDROID_SYSTEM_UI_RESOURCE_MANAGER_H_ diff --git a/ui/base/android/window_android_compositor.h b/ui/base/android/window_android_compositor.h index eb55a7b..eee3357 100644 --- a/ui/base/android/window_android_compositor.h +++ b/ui/base/android/window_android_compositor.h @@ -6,6 +6,7 @@ #define UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_ #include "cc/output/copy_output_request.h" +#include "ui/base/android/system_ui_resource_manager.h" #include "ui/base/ui_base_export.h" namespace cc { @@ -25,6 +26,7 @@ class UI_BASE_EXPORT WindowAndroidCompositor { virtual void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) = 0; virtual void SetNeedsAnimate() = 0; + virtual SystemUIResourceManager& GetSystemUIResourceManager() = 0; }; } // namespace ui diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp index 6e6a316..887e8e4 100644 --- a/ui/base/ui_base.gyp +++ b/ui/base/ui_base.gyp @@ -47,6 +47,7 @@ 'accelerators/platform_accelerator.h', 'accelerators/platform_accelerator_cocoa.h', 'accelerators/platform_accelerator_cocoa.mm', + 'android/system_ui_resource_manager.h', 'android/ui_base_jni_registrar.cc', 'android/ui_base_jni_registrar.h', 'android/view_android.cc', diff --git a/ui/gfx/android/java_bitmap.cc b/ui/gfx/android/java_bitmap.cc index 5988befe..d1f644f 100644 --- a/ui/gfx/android/java_bitmap.cc +++ b/ui/gfx/android/java_bitmap.cc @@ -9,6 +9,7 @@ #include "base/android/jni_string.h" #include "base/logging.h" #include "jni/BitmapHelper_jni.h" +#include "skia/ext/image_operations.h" #include "ui/gfx/size.h" using base::android::AttachCurrentThread; @@ -68,17 +69,6 @@ ScopedJavaLocalRef<jobject> CreateJavaBitmap(int width, AttachCurrentThread(), width, height, java_bitmap_config); } -ScopedJavaLocalRef<jobject> CreateJavaBitmapFromAndroidResource( - const char* name, - gfx::Size size) { - DCHECK(name); - DCHECK(!size.IsEmpty()); - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jstring> jname(ConvertUTF8ToJavaString(env, name)); - return Java_BitmapHelper_decodeDrawableResource( - env, jname.obj(), size.width(), size.height()); -} - ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) { DCHECK(skbitmap); DCHECK(!skbitmap->isNull()); @@ -96,6 +86,26 @@ ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) { return jbitmap; } +SkBitmap CreateSkBitmapFromAndroidResource(const char* name, gfx::Size size) { + DCHECK(name); + DCHECK(!size.IsEmpty()); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jstring> jname(ConvertUTF8ToJavaString(env, name)); + base::android::ScopedJavaLocalRef<jobject> jobj = + Java_BitmapHelper_decodeDrawableResource( + env, jname.obj(), size.width(), size.height()); + + if (jobj.is_null()) + return SkBitmap(); + + SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(jobj.obj())); + if (bitmap.isNull()) + return bitmap; + + return skia::ImageOperations::Resize( + bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height()); +} + SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap) { // TODO(jdduke): Convert to DCHECK's when sufficient data has been capture for // crbug.com/341406. diff --git a/ui/gfx/android/java_bitmap.h b/ui/gfx/android/java_bitmap.h index befb09b..34cd26a 100644 --- a/ui/gfx/android/java_bitmap.h +++ b/ui/gfx/android/java_bitmap.h @@ -57,12 +57,12 @@ GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> CreateJavaBitmap( int height, SkColorType color_type); -// Loads a Java-backed bitmap (android.graphics.Bitmap) from the provided -// drawable resource identifier (e.g., android:drawable/overscroll_glow). If the -// resource loads successfully, it will be integrally scaled down, preserving -// aspect ratio, to a size no smaller than |size|. Otherwise, null is returned. -GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> - CreateJavaBitmapFromAndroidResource(const char* name, gfx::Size size); +// Loads an SkBitmap from the provided drawable resource identifier (e.g., +// android:drawable/overscroll_glow). If the resource loads successfully, it +// will be integrally scaled down, preserving aspect ratio, to a size no smaller +// than |size|. Otherwise, an empty bitmap is returned. +GFX_EXPORT SkBitmap + CreateSkBitmapFromAndroidResource(const char* name, gfx::Size size); // Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap). // Note: |skbitmap| is assumed to be non-null, non-empty and one of RGBA_8888 or |