jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 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 "ui/android/resources/resource_manager_impl.h" |
| 6 | |
avi | 9c81217b | 2015-12-24 23:40:05 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 9 | #include <utility> |
| 10 | #include <vector> |
| 11 | |
| 12 | #include "base/android/jni_array.h" |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 13 | #include "base/android/jni_string.h" |
mdjones | 4adb368f | 2016-09-09 02:35:54 | [diff] [blame] | 14 | #include "base/memory/ptr_util.h" |
ssid | 334fb87a | 2015-01-27 20:12:07 | [diff] [blame] | 15 | #include "base/trace_event/trace_event.h" |
sievers | 148fedf | 2015-10-02 00:12:04 | [diff] [blame] | 16 | #include "cc/resources/scoped_ui_resource.h" |
khushalsagar | 8ec0740 | 2016-09-10 03:13:19 | [diff] [blame^] | 17 | #include "cc/resources/ui_resource_manager.h" |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 18 | #include "jni/ResourceManager_jni.h" |
mdjones | 4adb368f | 2016-09-09 02:35:54 | [diff] [blame] | 19 | #include "third_party/skia/include/core/SkBitmap.h" |
| 20 | #include "third_party/skia/include/core/SkCanvas.h" |
| 21 | #include "third_party/skia/include/core/SkColorFilter.h" |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 22 | #include "ui/android/resources/ui_resource_provider.h" |
gsennton | 44b7044 | 2015-11-17 12:44:12 | [diff] [blame] | 23 | #include "ui/android/window_android.h" |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 24 | #include "ui/gfx/android/java_bitmap.h" |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 25 | #include "ui/gfx/geometry/rect.h" |
| 26 | |
| 27 | using base::android::JavaArrayOfIntArrayToIntVector; |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 28 | using base::android::JavaRef; |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 29 | |
| 30 | namespace ui { |
| 31 | |
| 32 | // static |
| 33 | ResourceManagerImpl* ResourceManagerImpl::FromJavaObject(jobject jobj) { |
| 34 | return reinterpret_cast<ResourceManagerImpl*>( |
| 35 | Java_ResourceManager_getNativePtr(base::android::AttachCurrentThread(), |
| 36 | jobj)); |
| 37 | } |
| 38 | |
gsennton | 44b7044 | 2015-11-17 12:44:12 | [diff] [blame] | 39 | ResourceManagerImpl::ResourceManagerImpl(gfx::NativeWindow native_window) |
khushalsagar | 8ec0740 | 2016-09-10 03:13:19 | [diff] [blame^] | 40 | : ui_resource_manager_(nullptr) { |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 41 | JNIEnv* env = base::android::AttachCurrentThread(); |
torne | 948f366 | 2016-08-16 15:10:44 | [diff] [blame] | 42 | java_obj_.Reset( |
| 43 | env, Java_ResourceManager_create(env, native_window->GetJavaObject(), |
| 44 | reinterpret_cast<intptr_t>(this)) |
| 45 | .obj()); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 46 | DCHECK(!java_obj_.is_null()); |
| 47 | } |
| 48 | |
| 49 | ResourceManagerImpl::~ResourceManagerImpl() { |
torne | 948f366 | 2016-08-16 15:10:44 | [diff] [blame] | 50 | Java_ResourceManager_destroy(base::android::AttachCurrentThread(), java_obj_); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 51 | } |
| 52 | |
khushalsagar | 8ec0740 | 2016-09-10 03:13:19 | [diff] [blame^] | 53 | void ResourceManagerImpl::Init(cc::UIResourceManager* ui_resource_manager) { |
| 54 | DCHECK(!ui_resource_manager_); |
| 55 | DCHECK(ui_resource_manager); |
| 56 | ui_resource_manager_ = ui_resource_manager; |
sievers | 148fedf | 2015-10-02 00:12:04 | [diff] [blame] | 57 | } |
| 58 | |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 59 | base::android::ScopedJavaLocalRef<jobject> |
| 60 | ResourceManagerImpl::GetJavaObject() { |
| 61 | return base::android::ScopedJavaLocalRef<jobject>(java_obj_); |
| 62 | } |
| 63 | |
| 64 | ResourceManager::Resource* ResourceManagerImpl::GetResource( |
| 65 | AndroidResourceType res_type, |
| 66 | int res_id) { |
| 67 | DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| 68 | DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| 69 | |
| 70 | Resource* resource = resources_[res_type].Lookup(res_id); |
| 71 | |
| 72 | if (!resource || res_type == ANDROID_RESOURCE_TYPE_DYNAMIC || |
| 73 | res_type == ANDROID_RESOURCE_TYPE_DYNAMIC_BITMAP) { |
| 74 | RequestResourceFromJava(res_type, res_id); |
| 75 | resource = resources_[res_type].Lookup(res_id); |
| 76 | } |
| 77 | |
| 78 | return resource; |
| 79 | } |
| 80 | |
mdjones | 4adb368f | 2016-09-09 02:35:54 | [diff] [blame] | 81 | void ResourceManagerImpl::RemoveUnusedTints( |
| 82 | const std::unordered_set<int>& used_tints) { |
| 83 | // Iterate over the currently cached tints and remove ones that were not |
| 84 | // used as defined in |used_tints|. |
| 85 | for (auto it = tinted_resources_.cbegin(); it != tinted_resources_.cend();) { |
| 86 | if (used_tints.find(it->first) == used_tints.end()) { |
| 87 | it = tinted_resources_.erase(it); |
| 88 | } else { |
| 89 | ++it; |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | ResourceManager::Resource* ResourceManagerImpl::GetStaticResourceWithTint( |
| 95 | int res_id, |
| 96 | int tint_color) { |
| 97 | if (tinted_resources_.find(tint_color) == tinted_resources_.end()) { |
| 98 | tinted_resources_[tint_color] = base::MakeUnique<ResourceMap>(); |
| 99 | } |
| 100 | ResourceMap* resource_map = tinted_resources_[tint_color].get(); |
| 101 | |
| 102 | Resource* tinted_resource = resource_map->Lookup(res_id); |
| 103 | |
| 104 | // If the resource is already cached, use it. |
| 105 | if (tinted_resource) |
| 106 | return tinted_resource; |
| 107 | |
| 108 | tinted_resource = new Resource(); |
| 109 | |
| 110 | ResourceManager::Resource* base_image = |
| 111 | GetResource(ANDROID_RESOURCE_TYPE_STATIC, res_id); |
| 112 | DCHECK(base_image); |
| 113 | |
| 114 | TRACE_EVENT0("browser", "ResourceManagerImpl::GetStaticResourceWithTint"); |
| 115 | SkBitmap tinted_bitmap; |
| 116 | tinted_bitmap.allocPixels(SkImageInfo::MakeN32Premul(base_image->size.width(), |
| 117 | base_image->size.height())); |
| 118 | |
| 119 | SkCanvas canvas(tinted_bitmap); |
| 120 | canvas.clear(SK_ColorTRANSPARENT); |
| 121 | |
| 122 | // Build a color filter to use on the base resource. This filter multiplies |
| 123 | // the RGB components by the components of the new color but retains the |
| 124 | // alpha of the original image. |
| 125 | SkPaint color_filter; |
| 126 | color_filter.setColorFilter( |
| 127 | SkColorFilter::MakeModeFilter(tint_color, SkXfermode::kModulate_Mode)); |
| 128 | |
| 129 | // Draw the resource and make it immutable. |
| 130 | base_image->ui_resource->GetBitmap(base_image->ui_resource->id(), false) |
| 131 | .DrawToCanvas(&canvas, &color_filter); |
| 132 | tinted_bitmap.setImmutable(); |
| 133 | |
| 134 | // Create a UI resource from the new bitmap. |
| 135 | tinted_resource = new Resource(); |
| 136 | tinted_resource->size = gfx::Size(base_image->size); |
| 137 | tinted_resource->padding = gfx::Rect(base_image->padding); |
| 138 | tinted_resource->aperture = gfx::Rect(base_image->aperture); |
khushalsagar | 8ec0740 | 2016-09-10 03:13:19 | [diff] [blame^] | 139 | tinted_resource->ui_resource = cc::ScopedUIResource::Create( |
| 140 | ui_resource_manager_, cc::UIResourceBitmap(tinted_bitmap)); |
mdjones | 4adb368f | 2016-09-09 02:35:54 | [diff] [blame] | 141 | |
| 142 | resource_map->AddWithID(tinted_resource, res_id); |
| 143 | |
| 144 | return tinted_resource; |
| 145 | } |
| 146 | |
| 147 | void ResourceManagerImpl::ClearTintedResourceCache(JNIEnv* env, |
| 148 | const JavaRef<jobject>& jobj) { |
| 149 | tinted_resources_.clear(); |
| 150 | } |
| 151 | |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 152 | void ResourceManagerImpl::PreloadResource(AndroidResourceType res_type, |
| 153 | int res_id) { |
| 154 | DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| 155 | DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| 156 | |
| 157 | // Don't send out a query if the resource is already loaded. |
| 158 | if (resources_[res_type].Lookup(res_id)) |
| 159 | return; |
| 160 | |
| 161 | PreloadResourceFromJava(res_type, res_id); |
| 162 | } |
| 163 | |
| 164 | void ResourceManagerImpl::OnResourceReady(JNIEnv* env, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 165 | const JavaRef<jobject>& jobj, |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 166 | jint res_type, |
| 167 | jint res_id, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 168 | const JavaRef<jobject>& bitmap, |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 169 | jint padding_left, |
| 170 | jint padding_top, |
| 171 | jint padding_right, |
| 172 | jint padding_bottom, |
| 173 | jint aperture_left, |
| 174 | jint aperture_top, |
| 175 | jint aperture_right, |
| 176 | jint aperture_bottom) { |
| 177 | DCHECK_GE(res_type, ANDROID_RESOURCE_TYPE_FIRST); |
| 178 | DCHECK_LE(res_type, ANDROID_RESOURCE_TYPE_LAST); |
| 179 | TRACE_EVENT2("ui", "ResourceManagerImpl::OnResourceReady", |
| 180 | "resource_type", res_type, |
| 181 | "resource_id", res_id); |
| 182 | |
| 183 | Resource* resource = resources_[res_type].Lookup(res_id); |
| 184 | if (!resource) { |
| 185 | resource = new Resource(); |
| 186 | resources_[res_type].AddWithID(resource, res_id); |
| 187 | } |
| 188 | |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 189 | gfx::JavaBitmap jbitmap(bitmap.obj()); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 190 | resource->size = jbitmap.size(); |
| 191 | resource->padding.SetRect(padding_left, padding_top, |
| 192 | padding_right - padding_left, |
| 193 | padding_bottom - padding_top); |
| 194 | resource->aperture.SetRect(aperture_left, aperture_top, |
| 195 | aperture_right - aperture_left, |
| 196 | aperture_bottom - aperture_top); |
sievers | 148fedf | 2015-10-02 00:12:04 | [diff] [blame] | 197 | |
| 198 | SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(jbitmap); |
| 199 | skbitmap.setImmutable(); |
khushalsagar | 8ec0740 | 2016-09-10 03:13:19 | [diff] [blame^] | 200 | resource->ui_resource = cc::ScopedUIResource::Create( |
| 201 | ui_resource_manager_, cc::UIResourceBitmap(skbitmap)); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 202 | } |
| 203 | |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 204 | CrushedSpriteResource* ResourceManagerImpl::GetCrushedSpriteResource( |
| 205 | int bitmap_res_id, int metadata_res_id) { |
| 206 | CrushedSpriteResource* resource = |
| 207 | crushed_sprite_resources_.Lookup(bitmap_res_id); |
| 208 | if (!resource) { |
| 209 | RequestCrushedSpriteResourceFromJava(bitmap_res_id, metadata_res_id, false); |
| 210 | resource = crushed_sprite_resources_.Lookup(bitmap_res_id); |
| 211 | } else if (resource->BitmapHasBeenEvictedFromMemory()) { |
| 212 | RequestCrushedSpriteResourceFromJava(bitmap_res_id, metadata_res_id, true); |
| 213 | } |
| 214 | |
| 215 | return resource; |
| 216 | } |
| 217 | |
| 218 | void ResourceManagerImpl::OnCrushedSpriteResourceReady( |
| 219 | JNIEnv* env, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 220 | const JavaRef<jobject>& jobj, |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 221 | jint bitmap_res_id, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 222 | const JavaRef<jobject>& bitmap, |
| 223 | const JavaRef<jobjectArray>& frame_rects, |
twellington | f98ae6a | 2015-11-03 22:59:47 | [diff] [blame] | 224 | jint unscaled_sprite_width, |
| 225 | jint unscaled_sprite_height, |
| 226 | jfloat scaled_sprite_width, |
| 227 | jfloat scaled_sprite_height) { |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 228 | // Construct source and destination rectangles for each frame from |
| 229 | // |frame_rects|. |
| 230 | std::vector<std::vector<int>> all_frame_rects_vector; |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 231 | JavaArrayOfIntArrayToIntVector(env, frame_rects.obj(), |
| 232 | &all_frame_rects_vector); |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 233 | CrushedSpriteResource::SrcDstRects src_dst_rects = |
| 234 | ProcessCrushedSpriteFrameRects(all_frame_rects_vector); |
| 235 | |
| 236 | SkBitmap skbitmap = |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 237 | gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj())); |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 238 | |
| 239 | CrushedSpriteResource* resource = new CrushedSpriteResource( |
| 240 | skbitmap, |
| 241 | src_dst_rects, |
twellington | f98ae6a | 2015-11-03 22:59:47 | [diff] [blame] | 242 | gfx::Size(unscaled_sprite_width, unscaled_sprite_height), |
| 243 | gfx::Size(scaled_sprite_width, scaled_sprite_height)); |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 244 | |
| 245 | if (crushed_sprite_resources_.Lookup(bitmap_res_id)) { |
| 246 | crushed_sprite_resources_.Replace(bitmap_res_id, resource); |
| 247 | } else { |
| 248 | crushed_sprite_resources_.AddWithID(resource, bitmap_res_id); |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | CrushedSpriteResource::SrcDstRects |
| 253 | ResourceManagerImpl::ProcessCrushedSpriteFrameRects( |
| 254 | std::vector<std::vector<int>> frame_rects_vector) { |
| 255 | CrushedSpriteResource::SrcDstRects src_dst_rects; |
| 256 | for (size_t i = 0; i < frame_rects_vector.size(); ++i) { |
| 257 | std::vector<int> frame_ints = frame_rects_vector[i]; |
| 258 | CrushedSpriteResource::FrameSrcDstRects frame_src_dst_rects; |
| 259 | |
| 260 | // Create source and destination gfx::Rect's for each rectangle in |
| 261 | // |frame_ints|. Each rectangle consists of 6 values: |
| 262 | // i: destination x i+1: destination y i+2: source x i+3: source y |
| 263 | // i+4: width i+5: height |
| 264 | for (size_t j = 0; j < frame_ints.size(); j += 6) { |
| 265 | gfx::Rect sprite_rect_destination(frame_ints[j], |
| 266 | frame_ints[j+1], |
| 267 | frame_ints[j+4], |
| 268 | frame_ints[j+5]); |
| 269 | gfx::Rect sprite_rect_source(frame_ints[j+2], |
| 270 | frame_ints[j+3], |
| 271 | frame_ints[j+4], |
| 272 | frame_ints[j+5]); |
| 273 | frame_src_dst_rects.push_back(std::pair<gfx::Rect, gfx::Rect>( |
| 274 | sprite_rect_source, sprite_rect_destination)); |
| 275 | } |
| 276 | src_dst_rects.push_back(frame_src_dst_rects); |
| 277 | } |
| 278 | return src_dst_rects; |
| 279 | } |
| 280 | |
| 281 | void ResourceManagerImpl::OnCrushedSpriteResourceReloaded( |
| 282 | JNIEnv* env, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 283 | const JavaRef<jobject>& jobj, |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 284 | jint bitmap_res_id, |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 285 | const JavaRef<jobject>& bitmap) { |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 286 | CrushedSpriteResource* resource = |
| 287 | crushed_sprite_resources_.Lookup(bitmap_res_id); |
| 288 | if (!resource) { |
| 289 | // Cannot reload a resource that has not been previously loaded. |
| 290 | return; |
| 291 | } |
| 292 | SkBitmap skbitmap = |
torne | bb13c83 | 2015-12-07 12:49:14 | [diff] [blame] | 293 | gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj())); |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 294 | resource->SetBitmap(skbitmap); |
| 295 | } |
| 296 | |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 297 | // static |
| 298 | bool ResourceManagerImpl::RegisterResourceManager(JNIEnv* env) { |
| 299 | return RegisterNativesImpl(env); |
| 300 | } |
| 301 | |
| 302 | void ResourceManagerImpl::PreloadResourceFromJava(AndroidResourceType res_type, |
| 303 | int res_id) { |
| 304 | TRACE_EVENT2("ui", "ResourceManagerImpl::PreloadResourceFromJava", |
| 305 | "resource_type", res_type, |
| 306 | "resource_id", res_id); |
| 307 | Java_ResourceManager_preloadResource(base::android::AttachCurrentThread(), |
torne | 948f366 | 2016-08-16 15:10:44 | [diff] [blame] | 308 | java_obj_, res_type, res_id); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 309 | } |
| 310 | |
| 311 | void ResourceManagerImpl::RequestResourceFromJava(AndroidResourceType res_type, |
| 312 | int res_id) { |
| 313 | TRACE_EVENT2("ui", "ResourceManagerImpl::RequestResourceFromJava", |
| 314 | "resource_type", res_type, |
| 315 | "resource_id", res_id); |
| 316 | Java_ResourceManager_resourceRequested(base::android::AttachCurrentThread(), |
torne | 948f366 | 2016-08-16 15:10:44 | [diff] [blame] | 317 | java_obj_, res_type, res_id); |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 318 | } |
| 319 | |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 320 | void ResourceManagerImpl::RequestCrushedSpriteResourceFromJava( |
| 321 | int bitmap_res_id, int metadata_res_id, bool reloading) { |
| 322 | TRACE_EVENT2("ui", |
| 323 | "ResourceManagerImpl::RequestCrushedSpriteResourceFromJava", |
| 324 | "bitmap_res_id", bitmap_res_id, |
| 325 | "metadata_res_id", metadata_res_id); |
| 326 | Java_ResourceManager_crushedSpriteResourceRequested( |
torne | 948f366 | 2016-08-16 15:10:44 | [diff] [blame] | 327 | base::android::AttachCurrentThread(), java_obj_, bitmap_res_id, |
| 328 | metadata_res_id, reloading); |
twellington | af303ba | 2015-10-29 23:15:57 | [diff] [blame] | 329 | } |
| 330 | |
jdduke | 282f5e1 | 2014-12-19 23:39:49 | [diff] [blame] | 331 | } // namespace ui |