Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / android / compositor / tab_content_manager.cc
blob6746910b3821d899d5609c0b2242e41992dd208d
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.
5 #include "chrome/browser/android/compositor/tab_content_manager.h"
7 #include <android/bitmap.h>
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "cc/layers/layer.h"
15 #include "chrome/browser/android/compositor/layer/thumbnail_layer.h"
16 #include "chrome/browser/android/tab_android.h"
17 #include "chrome/browser/android/thumbnail/thumbnail.h"
18 #include "content/public/browser/android/content_view_core.h"
19 #include "content/public/browser/readback_types.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/web_contents.h"
22 #include "jni/TabContentManager_jni.h"
23 #include "ui/android/resources/ui_resource_provider.h"
24 #include "ui/gfx/android/java_bitmap.h"
25 #include "ui/gfx/geometry/rect.h"
26 #include "url/gurl.h"
28 namespace {
30 const size_t kMaxReadbacks = 1;
31 typedef base::Callback<void(float, const SkBitmap&)> TabReadbackCallback;
33 } // namespace
35 namespace chrome {
36 namespace android {
38 class TabContentManager::TabReadbackRequest {
39 public:
40 TabReadbackRequest(jobject content_view_core,
41 float thumbnail_scale,
42 const TabReadbackCallback& end_callback)
43 : thumbnail_scale_(thumbnail_scale),
44 end_callback_(end_callback),
45 drop_after_readback_(false),
46 weak_factory_(this) {
47 JNIEnv* env = base::android::AttachCurrentThread();
48 j_content_view_core_.Reset(env, content_view_core);
51 virtual ~TabReadbackRequest() {}
53 void Run() {
54 JNIEnv* env = base::android::AttachCurrentThread();
55 content::ReadbackRequestCallback result_callback =
56 base::Bind(&TabReadbackRequest::OnFinishGetTabThumbnailBitmap,
57 weak_factory_.GetWeakPtr());
59 if (j_content_view_core_.is_null()) {
60 result_callback.Run(SkBitmap(), content::READBACK_FAILED);
61 return;
64 content::ContentViewCore* view =
65 content::ContentViewCore::GetNativeContentViewCore(
66 env, j_content_view_core_.obj());
68 if (!view) {
69 result_callback.Run(SkBitmap(), content::READBACK_FAILED);
70 return;
73 DCHECK(view->GetWebContents());
74 view->GetWebContents()->GetRenderViewHost()->LockBackingStore();
76 SkColorType color_type = kN32_SkColorType;
78 // Calling this method with an empty rect will return a bitmap of the size
79 // of the content.
80 view->GetScaledContentBitmap(thumbnail_scale_, color_type, gfx::Rect(),
81 result_callback);
84 void OnFinishGetTabThumbnailBitmap(const SkBitmap& bitmap,
85 content::ReadbackResponse response) {
86 DCHECK(!j_content_view_core_.is_null());
87 JNIEnv* env = base::android::AttachCurrentThread();
88 content::ContentViewCore* view =
89 content::ContentViewCore::GetNativeContentViewCore(
90 env, j_content_view_core_.obj());
92 if (view) {
93 DCHECK(view->GetWebContents());
94 view->GetWebContents()->GetRenderViewHost()->UnlockBackingStore();
97 // TODO(jdduke): Tailor response to different failure values appropriately.
98 if (response != content::READBACK_SUCCESS || drop_after_readback_) {
99 end_callback_.Run(0.f, SkBitmap());
100 return;
103 SkBitmap result_bitmap = bitmap;
104 result_bitmap.setImmutable();
105 end_callback_.Run(thumbnail_scale_, bitmap);
108 void SetToDropAfterReadback() { drop_after_readback_ = true; }
110 private:
111 base::android::ScopedJavaGlobalRef<jobject> j_content_view_core_;
112 const float thumbnail_scale_;
113 TabReadbackCallback end_callback_;
114 bool drop_after_readback_;
116 base::WeakPtrFactory<TabReadbackRequest> weak_factory_;
118 DISALLOW_COPY_AND_ASSIGN(TabReadbackRequest);
121 // static
122 TabContentManager* TabContentManager::FromJavaObject(jobject jobj) {
123 if (!jobj)
124 return NULL;
125 return reinterpret_cast<TabContentManager*>(
126 Java_TabContentManager_getNativePtr(base::android::AttachCurrentThread(),
127 jobj));
130 TabContentManager::TabContentManager(JNIEnv* env,
131 jobject obj,
132 jint default_cache_size,
133 jint approximation_cache_size,
134 jint compression_queue_max_size,
135 jint write_queue_max_size,
136 jboolean use_approximation_thumbnail)
137 : weak_java_tab_content_manager_(env, obj), weak_factory_(this) {
138 thumbnail_cache_ = make_scoped_ptr(new ThumbnailCache(
139 (size_t)default_cache_size, (size_t)approximation_cache_size,
140 (size_t)compression_queue_max_size, (size_t)write_queue_max_size,
141 use_approximation_thumbnail));
142 thumbnail_cache_->AddThumbnailCacheObserver(this);
145 TabContentManager::~TabContentManager() {
148 void TabContentManager::Destroy(JNIEnv* env, jobject obj) {
149 thumbnail_cache_->RemoveThumbnailCacheObserver(this);
150 delete this;
153 void TabContentManager::SetUIResourceProvider(JNIEnv* env,
154 jobject obj,
155 jlong ui_resource_provider_ptr) {
156 ui::UIResourceProvider* ui_resource_provider =
157 reinterpret_cast<ui::UIResourceProvider*>(ui_resource_provider_ptr);
158 SetUIResourceProvider(ui_resource_provider);
161 void TabContentManager::SetUIResourceProvider(
162 ui::UIResourceProvider* ui_resource_provider) {
163 thumbnail_cache_->SetUIResourceProvider(ui_resource_provider);
166 scoped_refptr<cc::Layer> TabContentManager::GetLiveLayer(int tab_id) {
167 scoped_refptr<cc::Layer> layer = live_layer_list_[tab_id];
168 if (!layer.get())
169 return NULL;
171 return layer;
174 scoped_refptr<ThumbnailLayer> TabContentManager::GetStaticLayer(
175 int tab_id,
176 bool force_disk_read) {
177 Thumbnail* thumbnail = thumbnail_cache_->Get(tab_id, force_disk_read, true);
178 scoped_refptr<ThumbnailLayer> static_layer = static_layer_cache_[tab_id];
180 if (!thumbnail || !thumbnail->ui_resource_id()) {
181 if (static_layer.get()) {
182 static_layer->layer()->RemoveFromParent();
183 static_layer_cache_.erase(tab_id);
185 return NULL;
188 if (!static_layer.get()) {
189 static_layer = ThumbnailLayer::Create();
190 static_layer_cache_[tab_id] = static_layer;
193 static_layer->SetThumbnail(thumbnail);
194 return static_layer;
197 void TabContentManager::AttachLiveLayer(int tab_id,
198 scoped_refptr<cc::Layer> layer) {
199 if (!layer.get())
200 return;
202 scoped_refptr<cc::Layer> cached_layer = live_layer_list_[tab_id];
203 if (cached_layer != layer)
204 live_layer_list_[tab_id] = layer;
207 void TabContentManager::DetachLiveLayer(int tab_id,
208 scoped_refptr<cc::Layer> layer) {
209 scoped_refptr<cc::Layer> current_layer = live_layer_list_[tab_id];
210 if (!current_layer.get()) {
211 // Empty cached layer should not exist but it is ok if it happens.
212 return;
215 // We need to remove if we're getting a detach for our current layer or we're
216 // getting a detach with NULL and we have a current layer, which means remove
217 // all layers.
218 if (current_layer.get() &&
219 (layer.get() == current_layer.get() || !layer.get())) {
220 live_layer_list_.erase(tab_id);
224 void TabContentManager::OnFinishDecompressThumbnail(int tab_id,
225 bool success,
226 SkBitmap bitmap) {
227 JNIEnv* env = base::android::AttachCurrentThread();
228 ScopedJavaLocalRef<jobject> java_bitmap;
229 if (success)
230 java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
232 Java_TabContentManager_notifyDecompressBitmapFinished(
233 env, weak_java_tab_content_manager_.get(env).obj(), tab_id,
234 java_bitmap.obj());
237 jboolean TabContentManager::HasFullCachedThumbnail(JNIEnv* env,
238 jobject obj,
239 jint tab_id) {
240 return thumbnail_cache_->Get(tab_id, false, false) != nullptr;
243 void TabContentManager::CacheTab(JNIEnv* env,
244 jobject obj,
245 jobject tab,
246 jobject content_view_core,
247 jfloat thumbnail_scale) {
248 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, tab);
249 DCHECK(tab_android);
250 int tab_id = tab_android->GetAndroidId();
251 GURL url = tab_android->GetURL();
253 content::ContentViewCore* view =
254 content::ContentViewCore::GetNativeContentViewCore(env,
255 content_view_core);
257 if (thumbnail_cache_->CheckAndUpdateThumbnailMetaData(tab_id, url)) {
258 if (!view ||
259 !view->GetWebContents()
260 ->GetRenderViewHost()
261 ->CanCopyFromBackingStore() ||
262 pending_tab_readbacks_.find(tab_id) != pending_tab_readbacks_.end() ||
263 pending_tab_readbacks_.size() >= kMaxReadbacks) {
264 thumbnail_cache_->Remove(tab_id);
265 return;
268 TabReadbackCallback readback_done_callback =
269 base::Bind(&TabContentManager::PutThumbnailIntoCache,
270 weak_factory_.GetWeakPtr(), tab_id);
271 scoped_ptr<TabReadbackRequest> readback_request =
272 make_scoped_ptr(new TabReadbackRequest(
273 content_view_core, thumbnail_scale, readback_done_callback));
274 pending_tab_readbacks_.set(tab_id, readback_request.Pass());
275 pending_tab_readbacks_.get(tab_id)->Run();
279 void TabContentManager::CacheTabWithBitmap(JNIEnv* env,
280 jobject obj,
281 jobject tab,
282 jobject bitmap,
283 jfloat thumbnail_scale) {
284 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, tab);
285 DCHECK(tab_android);
286 int tab_id = tab_android->GetAndroidId();
287 GURL url = tab_android->GetURL();
289 gfx::JavaBitmap java_bitmap_lock(bitmap);
290 SkBitmap skbitmap = gfx::CreateSkBitmapFromJavaBitmap(java_bitmap_lock);
291 skbitmap.setImmutable();
293 if (thumbnail_cache_->CheckAndUpdateThumbnailMetaData(tab_id, url))
294 PutThumbnailIntoCache(tab_id, thumbnail_scale, skbitmap);
297 void TabContentManager::InvalidateIfChanged(JNIEnv* env,
298 jobject obj,
299 jint tab_id,
300 jstring jurl) {
301 thumbnail_cache_->InvalidateThumbnailIfChanged(
302 tab_id, GURL(base::android::ConvertJavaStringToUTF8(env, jurl)));
305 void TabContentManager::UpdateVisibleIds(JNIEnv* env,
306 jobject obj,
307 jintArray priority) {
308 std::list<int> priority_ids;
309 jsize length = env->GetArrayLength(priority);
310 jint* ints = env->GetIntArrayElements(priority, NULL);
311 for (jsize i = 0; i < length; ++i)
312 priority_ids.push_back(static_cast<int>(ints[i]));
314 env->ReleaseIntArrayElements(priority, ints, JNI_ABORT);
315 thumbnail_cache_->UpdateVisibleIds(priority_ids);
318 void TabContentManager::RemoveTabThumbnail(JNIEnv* env,
319 jobject obj,
320 jint tab_id) {
321 TabReadbackRequestMap::iterator readback_iter =
322 pending_tab_readbacks_.find(tab_id);
323 if (readback_iter != pending_tab_readbacks_.end())
324 readback_iter->second->SetToDropAfterReadback();
325 thumbnail_cache_->Remove(tab_id);
328 void TabContentManager::RemoveTabThumbnailFromDiskAtAndAboveId(
329 JNIEnv* env,
330 jobject obj,
331 jint min_forbidden_id) {
332 thumbnail_cache_->RemoveFromDiskAtAndAboveId(min_forbidden_id);
335 void TabContentManager::GetDecompressedThumbnail(JNIEnv* env,
336 jobject obj,
337 jint tab_id) {
338 base::Callback<void(bool, SkBitmap)> decompress_done_callback =
339 base::Bind(&TabContentManager::OnFinishDecompressThumbnail,
340 weak_factory_.GetWeakPtr(), reinterpret_cast<int>(tab_id));
341 thumbnail_cache_->DecompressThumbnailFromFile(reinterpret_cast<int>(tab_id),
342 decompress_done_callback);
345 void TabContentManager::OnFinishedThumbnailRead(int tab_id) {
346 JNIEnv* env = base::android::AttachCurrentThread();
347 Java_TabContentManager_notifyListenersOfThumbnailChange(
348 env, weak_java_tab_content_manager_.get(env).obj(), tab_id);
351 void TabContentManager::PutThumbnailIntoCache(int tab_id,
352 float thumbnail_scale,
353 const SkBitmap& bitmap) {
354 TabReadbackRequestMap::iterator readback_iter =
355 pending_tab_readbacks_.find(tab_id);
357 if (readback_iter != pending_tab_readbacks_.end())
358 pending_tab_readbacks_.erase(tab_id);
360 if (thumbnail_scale > 0 && !bitmap.empty())
361 thumbnail_cache_->Put(tab_id, bitmap, thumbnail_scale);
364 bool RegisterTabContentManager(JNIEnv* env) {
365 return RegisterNativesImpl(env);
368 // ----------------------------------------------------------------------------
369 // Native JNI methods
370 // ----------------------------------------------------------------------------
372 jlong Init(JNIEnv* env,
373 const JavaParamRef<jobject>& obj,
374 jint default_cache_size,
375 jint approximation_cache_size,
376 jint compression_queue_max_size,
377 jint write_queue_max_size,
378 jboolean use_approximation_thumbnail) {
379 TabContentManager* manager = new TabContentManager(
380 env, obj, default_cache_size, approximation_cache_size,
381 compression_queue_max_size, write_queue_max_size,
382 use_approximation_thumbnail);
383 return reinterpret_cast<intptr_t>(manager);
386 } // namespace android
387 } // namespace chrome