blob: 7a903740448c0c84c6c5681007005334fa2238d9 [file] [log] [blame]
jdduke282f5e12014-12-19 23:39:491// 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
avi9c81217b2015-12-24 23:40:057#include <stddef.h>
8
twellingtonaf303ba2015-10-29 23:15:579#include <utility>
10#include <vector>
11
12#include "base/android/jni_array.h"
jdduke282f5e12014-12-19 23:39:4913#include "base/android/jni_string.h"
mdjones4adb368f2016-09-09 02:35:5414#include "base/memory/ptr_util.h"
ssid334fb87a2015-01-27 20:12:0715#include "base/trace_event/trace_event.h"
sievers148fedf2015-10-02 00:12:0416#include "cc/resources/scoped_ui_resource.h"
khushalsagar8ec07402016-09-10 03:13:1917#include "cc/resources/ui_resource_manager.h"
jdduke282f5e12014-12-19 23:39:4918#include "jni/ResourceManager_jni.h"
mdjones4adb368f2016-09-09 02:35:5419#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"
jdduke282f5e12014-12-19 23:39:4922#include "ui/android/resources/ui_resource_provider.h"
gsennton44b70442015-11-17 12:44:1223#include "ui/android/window_android.h"
jdduke282f5e12014-12-19 23:39:4924#include "ui/gfx/android/java_bitmap.h"
twellingtonaf303ba2015-10-29 23:15:5725#include "ui/gfx/geometry/rect.h"
26
27using base::android::JavaArrayOfIntArrayToIntVector;
tornebb13c832015-12-07 12:49:1428using base::android::JavaRef;
jdduke282f5e12014-12-19 23:39:4929
30namespace ui {
31
32// static
33ResourceManagerImpl* ResourceManagerImpl::FromJavaObject(jobject jobj) {
34 return reinterpret_cast<ResourceManagerImpl*>(
35 Java_ResourceManager_getNativePtr(base::android::AttachCurrentThread(),
36 jobj));
37}
38
gsennton44b70442015-11-17 12:44:1239ResourceManagerImpl::ResourceManagerImpl(gfx::NativeWindow native_window)
khushalsagar8ec07402016-09-10 03:13:1940 : ui_resource_manager_(nullptr) {
jdduke282f5e12014-12-19 23:39:4941 JNIEnv* env = base::android::AttachCurrentThread();
torne948f3662016-08-16 15:10:4442 java_obj_.Reset(
43 env, Java_ResourceManager_create(env, native_window->GetJavaObject(),
44 reinterpret_cast<intptr_t>(this))
45 .obj());
jdduke282f5e12014-12-19 23:39:4946 DCHECK(!java_obj_.is_null());
47}
48
49ResourceManagerImpl::~ResourceManagerImpl() {
torne948f3662016-08-16 15:10:4450 Java_ResourceManager_destroy(base::android::AttachCurrentThread(), java_obj_);
jdduke282f5e12014-12-19 23:39:4951}
52
khushalsagar8ec07402016-09-10 03:13:1953void ResourceManagerImpl::Init(cc::UIResourceManager* ui_resource_manager) {
54 DCHECK(!ui_resource_manager_);
55 DCHECK(ui_resource_manager);
56 ui_resource_manager_ = ui_resource_manager;
sievers148fedf2015-10-02 00:12:0457}
58
jdduke282f5e12014-12-19 23:39:4959base::android::ScopedJavaLocalRef<jobject>
60ResourceManagerImpl::GetJavaObject() {
61 return base::android::ScopedJavaLocalRef<jobject>(java_obj_);
62}
63
64ResourceManager::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
mdjones4adb368f2016-09-09 02:35:5481void 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
94ResourceManager::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);
khushalsagar8ec07402016-09-10 03:13:19139 tinted_resource->ui_resource = cc::ScopedUIResource::Create(
140 ui_resource_manager_, cc::UIResourceBitmap(tinted_bitmap));
mdjones4adb368f2016-09-09 02:35:54141
142 resource_map->AddWithID(tinted_resource, res_id);
143
144 return tinted_resource;
145}
146
147void ResourceManagerImpl::ClearTintedResourceCache(JNIEnv* env,
148 const JavaRef<jobject>& jobj) {
149 tinted_resources_.clear();
150}
151
jdduke282f5e12014-12-19 23:39:49152void 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
164void ResourceManagerImpl::OnResourceReady(JNIEnv* env,
tornebb13c832015-12-07 12:49:14165 const JavaRef<jobject>& jobj,
jdduke282f5e12014-12-19 23:39:49166 jint res_type,
167 jint res_id,
tornebb13c832015-12-07 12:49:14168 const JavaRef<jobject>& bitmap,
jdduke282f5e12014-12-19 23:39:49169 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
tornebb13c832015-12-07 12:49:14189 gfx::JavaBitmap jbitmap(bitmap.obj());
jdduke282f5e12014-12-19 23:39:49190 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);
sievers148fedf2015-10-02 00:12:04197
198 SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(jbitmap);
199 skbitmap.setImmutable();
khushalsagar8ec07402016-09-10 03:13:19200 resource->ui_resource = cc::ScopedUIResource::Create(
201 ui_resource_manager_, cc::UIResourceBitmap(skbitmap));
jdduke282f5e12014-12-19 23:39:49202}
203
twellingtonaf303ba2015-10-29 23:15:57204CrushedSpriteResource* 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
218void ResourceManagerImpl::OnCrushedSpriteResourceReady(
219 JNIEnv* env,
tornebb13c832015-12-07 12:49:14220 const JavaRef<jobject>& jobj,
twellingtonaf303ba2015-10-29 23:15:57221 jint bitmap_res_id,
tornebb13c832015-12-07 12:49:14222 const JavaRef<jobject>& bitmap,
223 const JavaRef<jobjectArray>& frame_rects,
twellingtonf98ae6a2015-11-03 22:59:47224 jint unscaled_sprite_width,
225 jint unscaled_sprite_height,
226 jfloat scaled_sprite_width,
227 jfloat scaled_sprite_height) {
twellingtonaf303ba2015-10-29 23:15:57228 // Construct source and destination rectangles for each frame from
229 // |frame_rects|.
230 std::vector<std::vector<int>> all_frame_rects_vector;
tornebb13c832015-12-07 12:49:14231 JavaArrayOfIntArrayToIntVector(env, frame_rects.obj(),
232 &all_frame_rects_vector);
twellingtonaf303ba2015-10-29 23:15:57233 CrushedSpriteResource::SrcDstRects src_dst_rects =
234 ProcessCrushedSpriteFrameRects(all_frame_rects_vector);
235
236 SkBitmap skbitmap =
tornebb13c832015-12-07 12:49:14237 gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj()));
twellingtonaf303ba2015-10-29 23:15:57238
239 CrushedSpriteResource* resource = new CrushedSpriteResource(
240 skbitmap,
241 src_dst_rects,
twellingtonf98ae6a2015-11-03 22:59:47242 gfx::Size(unscaled_sprite_width, unscaled_sprite_height),
243 gfx::Size(scaled_sprite_width, scaled_sprite_height));
twellingtonaf303ba2015-10-29 23:15:57244
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
252CrushedSpriteResource::SrcDstRects
253ResourceManagerImpl::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
281void ResourceManagerImpl::OnCrushedSpriteResourceReloaded(
282 JNIEnv* env,
tornebb13c832015-12-07 12:49:14283 const JavaRef<jobject>& jobj,
twellingtonaf303ba2015-10-29 23:15:57284 jint bitmap_res_id,
tornebb13c832015-12-07 12:49:14285 const JavaRef<jobject>& bitmap) {
twellingtonaf303ba2015-10-29 23:15:57286 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 =
tornebb13c832015-12-07 12:49:14293 gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(bitmap.obj()));
twellingtonaf303ba2015-10-29 23:15:57294 resource->SetBitmap(skbitmap);
295}
296
jdduke282f5e12014-12-19 23:39:49297// static
298bool ResourceManagerImpl::RegisterResourceManager(JNIEnv* env) {
299 return RegisterNativesImpl(env);
300}
301
302void 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(),
torne948f3662016-08-16 15:10:44308 java_obj_, res_type, res_id);
jdduke282f5e12014-12-19 23:39:49309}
310
311void 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(),
torne948f3662016-08-16 15:10:44317 java_obj_, res_type, res_id);
jdduke282f5e12014-12-19 23:39:49318}
319
twellingtonaf303ba2015-10-29 23:15:57320void 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(
torne948f3662016-08-16 15:10:44327 base::android::AttachCurrentThread(), java_obj_, bitmap_res_id,
328 metadata_res_id, reloading);
twellingtonaf303ba2015-10-29 23:15:57329}
330
jdduke282f5e12014-12-19 23:39:49331} // namespace ui