| // 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 "ui/android/resources/resource_manager_impl.h" |
| |
| #include <stddef.h> |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/android/jni_array.h" |
| #include "base/android/jni_string.h" |
| #include "base/trace_event/trace_event.h" |
| #include "cc/resources/scoped_ui_resource.h" |
| #include "jni/ResourceManager_jni.h" |
| #include "ui/android/resources/ui_resource_provider.h" |
| #include "ui/android/window_android.h" |
| #include "ui/gfx/android/java_bitmap.h" |
| #include "ui/gfx/geometry/rect.h" |
| |
| using base::android::JavaArrayOfIntArrayToIntVector; |
| using base::android::JavaRef; |
| |
| namespace ui { |
| |
| // static |
| ResourceManagerImpl* ResourceManagerImpl::FromJavaObject(jobject jobj) { |
| return reinterpret_cast<ResourceManagerImpl*>( |
| Java_ResourceManager_getNativePtr(base::android::AttachCurrentThread(), |
| jobj)); |
| } |
| |
| ResourceManagerImpl::ResourceManagerImpl(gfx::NativeWindow native_window) |
| : host_(nullptr) { |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| java_obj_.Reset(env, Java_ResourceManager_create( |
| env, native_window->GetJavaObject().obj(), |
| reinterpret_cast<intptr_t>(this)) |
| .obj()); |
| DCHECK(!java_obj_.is_null()); |
| } |
| |
| ResourceManagerImpl::~ResourceManagerImpl() { |
| Java_ResourceManager_destroy(base::android::AttachCurrentThread(), |
| java_obj_.obj()); |
| } |
| |
| void ResourceManagerImpl::Init(cc::LayerTreeHost* host) { |
| DCHECK(!host_); |
| DCHECK(host); |
| host_ = host; |
| } |
| |
| base::android::ScopedJavaLocalRef<jobject> |
| ResourceManagerImpl::GetJavaObject() { |
| return base::android::ScopedJavaLocalRef<jobject>(java_obj_); |
| } |
| |
| ResourceManager::Resource* ResourceManagerImpl::GetResource( |
| AndroidResourceType res_type, |
| int res_id) { |
| DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| |
| Resource* resource = resources_[res_type].Lookup(res_id); |
| |
| if (!resource || res_type == ANDROID_RESOURCE_TYPE_DYNAMIC || |
| res_type == ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP) { |
| RequestResourceFromJava(res_type, res_id); |
| resource = resources_[res_type].Lookup(res_id); |
| } |
| |
| return resource; |
| } |
| |
| void ResourceManagerImpl::PreloadResource(AndroidResourceType res_type, |
| int res_id) { |
| DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| |
| // Don't send out a query if the resource is already loaded. |
| if (resources_[res_type].Lookup(res_id)) |
| return; |
| |
| PreloadResourceFromJava(res_type, res_id); |
| } |
| |
| void ResourceManagerImpl::OnResourceReady(JNIEnv* env, |
| const JavaRef<jobject>& jobj, |
| jint res_type, |
| jint res_id, |
| const JavaRef<jobject>& bitmap, |
| jint padding_left, |
| jint padding_top, |
| jint padding_right, |
| jint padding_bottom, |
| jint aperture_left, |
| jint aperture_top, |
| jint aperture_right, |
| jint aperture_bottom) { |
| DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| TRACE_EVENT2("ui", "ResourceManagerImpl::OnResourceReady", |
| "resource_type", res_type, |
| "resource_id", res_id); |
| |
| Resource* resource = resources_[res_type].Lookup(res_id); |
| if (!resource) { |
| resource = new Resource(); |
| resources_[res_type].AddWithID(resource, res_id); |
| } |
| |
| gfx::JavaBitmap jbitmap(bitmap.obj()); |
| resource->size = jbitmap.size(); |
| resource->padding.SetRect(padding_left, padding_top, |
| padding_right - padding_left, |
| padding_bottom - padding_top); |
| resource->aperture.SetRect(aperture_left, aperture_top, |
| aperture_right - aperture_left, |
| aperture_bottom - aperture_top); |
| |
| SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(jbitmap); |
| skbitmap.setImmutable(); |
| resource->ui_resource = |
| cc::ScopedUIResource::Create(host_, cc::UIResourceBitmap(skbitmap)); |
| } |
| |
| CrushedSpriteResource* ResourceManagerImpl::GetCrushedSpriteResource( |
| int bitmap_res_id, int metadata_res_id) { |
| CrushedSpriteResource* resource = |
| crushed_sprite_resources_.Lookup(bitmap_res_id); |
| if (!resource) { |
| RequestCrushedSpriteResourceFromJava(bitmap_res_id, metadata_res_id, false); |
| resource = crushed_sprite_resources_.Lookup(bitmap_res_id); |
| } else if (resource->BitmapHasBeenEvictedFromMemory()) { |
| RequestCrushedSpriteResourceFromJava(bitmap_res_id, metadata_res_id, true); |
| } |
| |
| return resource; |
| } |
| |
| void ResourceManagerImpl::OnCrushedSpriteResourceReady( |
| JNIEnv* env, |
| const JavaRef<jobject>& jobj, |
| jint bitmap_res_id, |
| const JavaRef<jobject>& bitmap, |
| const JavaRef<jobjectArray>& frame_rects, |
| jint unscaled_sprite_width, |
| jint unscaled_sprite_height, |
| jfloat scaled_sprite_width, |
| jfloat scaled_sprite_height) { |
| // Construct source and destination rectangles for each frame from |
| // |frame_rects|. |
| std::vector<std::vector<int>> all_frame_rects_vector; |
| JavaArrayOfIntArrayToIntVector(env, frame_rects.obj(), |
| &all_frame_rects_vector); |
| CrushedSpriteResource::SrcDstRects src_dst_rects = |
| ProcessCrushedSpriteFrameRects(all_frame_rects_vector); |
| |
| SkBitmap skbitmap = |
| gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj())); |
| |
| CrushedSpriteResource* resource = new CrushedSpriteResource( |
| skbitmap, |
| src_dst_rects, |
| gfx::Size(unscaled_sprite_width, unscaled_sprite_height), |
| gfx::Size(scaled_sprite_width, scaled_sprite_height)); |
| |
| if (crushed_sprite_resources_.Lookup(bitmap_res_id)) { |
| crushed_sprite_resources_.Replace(bitmap_res_id, resource); |
| } else { |
| crushed_sprite_resources_.AddWithID(resource, bitmap_res_id); |
| } |
| } |
| |
| CrushedSpriteResource::SrcDstRects |
| ResourceManagerImpl::ProcessCrushedSpriteFrameRects( |
| std::vector<std::vector<int>> frame_rects_vector) { |
| CrushedSpriteResource::SrcDstRects src_dst_rects; |
| for (size_t i = 0; i < frame_rects_vector.size(); ++i) { |
| std::vector<int> frame_ints = frame_rects_vector[i]; |
| CrushedSpriteResource::FrameSrcDstRects frame_src_dst_rects; |
| |
| // Create source and destination gfx::Rect's for each rectangle in |
| // |frame_ints|. Each rectangle consists of 6 values: |
| // i: destination x i+1: destination y i+2: source x i+3: source y |
| // i+4: width i+5: height |
| for (size_t j = 0; j < frame_ints.size(); j += 6) { |
| gfx::Rect sprite_rect_destination(frame_ints[j], |
| frame_ints[j+1], |
| frame_ints[j+4], |
| frame_ints[j+5]); |
| gfx::Rect sprite_rect_source(frame_ints[j+2], |
| frame_ints[j+3], |
| frame_ints[j+4], |
| frame_ints[j+5]); |
| frame_src_dst_rects.push_back(std::pair<gfx::Rect, gfx::Rect>( |
| sprite_rect_source, sprite_rect_destination)); |
| } |
| src_dst_rects.push_back(frame_src_dst_rects); |
| } |
| return src_dst_rects; |
| } |
| |
| void ResourceManagerImpl::OnCrushedSpriteResourceReloaded( |
| JNIEnv* env, |
| const JavaRef<jobject>& jobj, |
| jint bitmap_res_id, |
| const JavaRef<jobject>& bitmap) { |
| CrushedSpriteResource* resource = |
| crushed_sprite_resources_.Lookup(bitmap_res_id); |
| if (!resource) { |
| // Cannot reload a resource that has not been previously loaded. |
| return; |
| } |
| SkBitmap skbitmap = |
| gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj())); |
| resource->SetBitmap(skbitmap); |
| } |
| |
| // static |
| bool ResourceManagerImpl::RegisterResourceManager(JNIEnv* env) { |
| return RegisterNativesImpl(env); |
| } |
| |
| void ResourceManagerImpl::PreloadResourceFromJava(AndroidResourceType res_type, |
| int res_id) { |
| TRACE_EVENT2("ui", "ResourceManagerImpl::PreloadResourceFromJava", |
| "resource_type", res_type, |
| "resource_id", res_id); |
| Java_ResourceManager_preloadResource(base::android::AttachCurrentThread(), |
| java_obj_.obj(), res_type, res_id); |
| } |
| |
| void ResourceManagerImpl::RequestResourceFromJava(AndroidResourceType res_type, |
| int res_id) { |
| TRACE_EVENT2("ui", "ResourceManagerImpl::RequestResourceFromJava", |
| "resource_type", res_type, |
| "resource_id", res_id); |
| Java_ResourceManager_resourceRequested(base::android::AttachCurrentThread(), |
| java_obj_.obj(), res_type, res_id); |
| } |
| |
| void ResourceManagerImpl::RequestCrushedSpriteResourceFromJava( |
| int bitmap_res_id, int metadata_res_id, bool reloading) { |
| TRACE_EVENT2("ui", |
| "ResourceManagerImpl::RequestCrushedSpriteResourceFromJava", |
| "bitmap_res_id", bitmap_res_id, |
| "metadata_res_id", metadata_res_id); |
| Java_ResourceManager_crushedSpriteResourceRequested( |
| base::android::AttachCurrentThread(), java_obj_.obj(), |
| bitmap_res_id, metadata_res_id, reloading); |
| } |
| |
| } // namespace ui |