1 // Copyright (c) 2012 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 "weblayer/browser/content_view_render_view.h"
6 
7 #include <android/bitmap.h>
8 #include <android/native_window_jni.h>
9 
10 #include <memory>
11 #include <utility>
12 
13 #include "base/android/jni_android.h"
14 #include "base/android/jni_string.h"
15 #include "base/android/scoped_java_ref.h"
16 #include "base/bind.h"
17 #include "base/lazy_instance.h"
18 #include "cc/layers/layer.h"
19 #include "cc/layers/picture_layer.h"
20 #include "content/public/browser/android/compositor.h"
21 #include "content/public/browser/web_contents.h"
22 #include "ui/android/resources/resource_manager.h"
23 #include "ui/android/view_android.h"
24 #include "ui/android/window_android.h"
25 #include "ui/gfx/android/java_bitmap.h"
26 #include "ui/gfx/geometry/size.h"
27 #include "weblayer/browser/java/jni/ContentViewRenderView_jni.h"
28 
29 using base::android::JavaParamRef;
30 using base::android::ScopedJavaLocalRef;
31 
32 namespace weblayer {
33 
ContentViewRenderView(JNIEnv * env,jobject obj,gfx::NativeWindow root_window)34 ContentViewRenderView::ContentViewRenderView(JNIEnv* env,
35                                              jobject obj,
36                                              gfx::NativeWindow root_window)
37     : root_window_(root_window) {
38   java_obj_.Reset(env, obj);
39 }
40 
~ContentViewRenderView()41 ContentViewRenderView::~ContentViewRenderView() {
42   DCHECK(height_changed_listener_.is_null());
43 }
44 
SetHeightChangedListener(base::RepeatingClosure callback)45 void ContentViewRenderView::SetHeightChangedListener(
46     base::RepeatingClosure callback) {
47   DCHECK(height_changed_listener_.is_null() || callback.is_null());
48   height_changed_listener_ = std::move(callback);
49 }
50 
51 // static
JNI_ContentViewRenderView_Init(JNIEnv * env,const JavaParamRef<jobject> & obj,const JavaParamRef<jobject> & jroot_window_android)52 static jlong JNI_ContentViewRenderView_Init(
53     JNIEnv* env,
54     const JavaParamRef<jobject>& obj,
55     const JavaParamRef<jobject>& jroot_window_android) {
56   gfx::NativeWindow root_window =
57       ui::WindowAndroid::FromJavaWindowAndroid(jroot_window_android);
58   ContentViewRenderView* content_view_render_view =
59       new ContentViewRenderView(env, obj, root_window);
60   return reinterpret_cast<intptr_t>(content_view_render_view);
61 }
62 
Destroy(JNIEnv * env)63 void ContentViewRenderView::Destroy(JNIEnv* env) {
64   delete this;
65 }
66 
SetCurrentWebContents(JNIEnv * env,const JavaParamRef<jobject> & jweb_contents)67 void ContentViewRenderView::SetCurrentWebContents(
68     JNIEnv* env,
69     const JavaParamRef<jobject>& jweb_contents) {
70   InitCompositor();
71   content::WebContents* web_contents =
72       content::WebContents::FromJavaWebContents(jweb_contents);
73   if (web_contents_layer_)
74     web_contents_layer_->RemoveFromParent();
75   web_contents_layer_ = web_contents ? web_contents->GetNativeView()->GetLayer()
76                                      : scoped_refptr<cc::Layer>();
77 
78   if (web_contents_layer_)
79     root_container_layer_->AddChild(web_contents_layer_);
80 }
81 
OnPhysicalBackingSizeChanged(JNIEnv * env,const JavaParamRef<jobject> & jweb_contents,jint width,jint height,jboolean for_config_change)82 void ContentViewRenderView::OnPhysicalBackingSizeChanged(
83     JNIEnv* env,
84     const JavaParamRef<jobject>& jweb_contents,
85     jint width,
86     jint height,
87     jboolean for_config_change) {
88   bool height_changed = height_ != height;
89   height_ = height;
90   content::WebContents* web_contents =
91       content::WebContents::FromJavaWebContents(jweb_contents);
92   gfx::Size size(width, height);
93 
94   // The default resize timeout on Android is 1s. It was chosen with browser
95   // use case in mind where resize is rare (eg orientation change, fullscreen)
96   // and users are generally willing to wait for those cases instead of seeing
97   // a frame at the wrong size. Weblayer currently can be resized while user
98   // is interacting with the page, in which case the timeout is too long.
99   // For now, use the default long timeout only for rotation (ie config change)
100   // and just use a zero timeout for all other cases.
101   base::Optional<base::TimeDelta> override_deadline;
102   if (!for_config_change)
103     override_deadline = base::TimeDelta();
104   web_contents->GetNativeView()->OnPhysicalBackingSizeChanged(
105       size, override_deadline);
106 
107   if (height_changed && !height_changed_listener_.is_null())
108     height_changed_listener_.Run();
109 }
110 
SurfaceCreated(JNIEnv * env)111 void ContentViewRenderView::SurfaceCreated(JNIEnv* env) {
112   InitCompositor();
113   current_surface_format_ = 0;
114 }
115 
SurfaceDestroyed(JNIEnv * env,jboolean cache_back_buffer)116 void ContentViewRenderView::SurfaceDestroyed(JNIEnv* env,
117                                              jboolean cache_back_buffer) {
118   if (cache_back_buffer)
119     compositor_->CacheBackBufferForCurrentSurface();
120   compositor_->SetSurface(nullptr, false);
121   current_surface_format_ = 0;
122 }
123 
SurfaceChanged(JNIEnv * env,jboolean can_be_used_with_surface_control,jint format,jint width,jint height,const JavaParamRef<jobject> & surface)124 void ContentViewRenderView::SurfaceChanged(
125     JNIEnv* env,
126     jboolean can_be_used_with_surface_control,
127     jint format,
128     jint width,
129     jint height,
130     const JavaParamRef<jobject>& surface) {
131   current_surface_format_ = format;
132   compositor_->SetSurface(surface, can_be_used_with_surface_control);
133   compositor_->SetWindowBounds(gfx::Size(width, height));
134 }
135 
SetNeedsRedraw(JNIEnv * env)136 void ContentViewRenderView::SetNeedsRedraw(JNIEnv* env) {
137   compositor_->SetNeedsRedraw();
138 }
139 
140 base::android::ScopedJavaLocalRef<jobject>
GetResourceManager(JNIEnv * env)141 ContentViewRenderView::GetResourceManager(JNIEnv* env) {
142   return compositor_->GetResourceManager().GetJavaObject();
143 }
144 
UpdateBackgroundColor(JNIEnv * env)145 void ContentViewRenderView::UpdateBackgroundColor(JNIEnv* env) {
146   if (!compositor_)
147     return;
148   compositor_->SetBackgroundColor(
149       Java_ContentViewRenderView_getBackgroundColor(env, java_obj_));
150 }
151 
UpdateLayerTreeHost()152 void ContentViewRenderView::UpdateLayerTreeHost() {
153   // TODO(wkorman): Rename Layout to UpdateLayerTreeHost in all Android
154   // Compositor related classes.
155 }
156 
DidSwapFrame(int pending_frames)157 void ContentViewRenderView::DidSwapFrame(int pending_frames) {
158   JNIEnv* env = base::android::AttachCurrentThread();
159   TRACE_EVENT0("weblayer", "Java_ContentViewRenderView_didSwapFrame");
160   if (Java_ContentViewRenderView_didSwapFrame(env, java_obj_)) {
161     compositor_->SetNeedsRedraw();
162   }
163 }
164 
DidSwapBuffers(const gfx::Size & swap_size)165 void ContentViewRenderView::DidSwapBuffers(const gfx::Size& swap_size) {
166   JNIEnv* env = base::android::AttachCurrentThread();
167   bool matches_window_bounds = swap_size == compositor_->GetWindowBounds();
168   Java_ContentViewRenderView_didSwapBuffers(env, java_obj_,
169                                             matches_window_bounds);
170 }
171 
EvictCachedSurface(JNIEnv * env)172 void ContentViewRenderView::EvictCachedSurface(JNIEnv* env) {
173   compositor_->EvictCachedBackBuffer();
174 }
175 
InitCompositor()176 void ContentViewRenderView::InitCompositor() {
177   if (compositor_)
178     return;
179 
180   compositor_.reset(content::Compositor::Create(this, root_window_));
181   root_container_layer_ = cc::Layer::Create();
182   root_container_layer_->SetHitTestable(false);
183   root_container_layer_->SetElementId(
184       cc::ElementId(root_container_layer_->id()));
185   root_container_layer_->SetIsDrawable(false);
186   compositor_->SetRootLayer(root_container_layer_);
187   UpdateBackgroundColor(base::android::AttachCurrentThread());
188 }
189 
190 }  // namespace weblayer
191