1 // Copyright 2013 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 "android_webview/browser/in_process_view_renderer.h"
7 #include <android/bitmap.h>
9 #include "android_webview/browser/aw_gl_surface.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/common/aw_switches.h"
12 #include "android_webview/public/browser/draw_gl.h"
13 #include "android_webview/public/browser/draw_sw.h"
14 #include "base/android/jni_android.h"
15 #include "base/auto_reset.h"
16 #include "base/command_line.h"
17 #include "base/debug/trace_event.h"
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/stringprintf.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/content_switches.h"
25 #include "gpu/command_buffer/service/in_process_command_buffer.h"
26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "third_party/skia/include/core/SkBitmapDevice.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h"
31 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
32 #include "ui/gfx/skia_util.h"
33 #include "ui/gfx/transform.h"
34 #include "ui/gfx/vector2d_conversions.h"
35 #include "ui/gfx/vector2d_f.h"
37 using base::android::AttachCurrentThread
;
38 using base::android::JavaRef
;
39 using base::android::ScopedJavaLocalRef
;
40 using content::BrowserThread
;
42 namespace android_webview
{
47 const void* kUserDataKey
= &kUserDataKey
;
49 class UserData
: public content::WebContents::Data
{
51 UserData(InProcessViewRenderer
* ptr
) : instance_(ptr
) {}
53 instance_
->WebContentsGone();
56 static InProcessViewRenderer
* GetInstance(content::WebContents
* contents
) {
59 UserData
* data
= reinterpret_cast<UserData
*>(
60 contents
->GetUserData(kUserDataKey
));
61 return data
? data
->instance_
: NULL
;
65 InProcessViewRenderer
* instance_
;
68 bool RasterizeIntoBitmap(JNIEnv
* env
,
69 const JavaRef
<jobject
>& jbitmap
,
72 const InProcessViewRenderer::RenderMethod
& renderer
) {
73 DCHECK(jbitmap
.obj());
75 AndroidBitmapInfo bitmap_info
;
76 if (AndroidBitmap_getInfo(env
, jbitmap
.obj(), &bitmap_info
) < 0) {
77 LOG(ERROR
) << "Error getting java bitmap info.";
82 if (AndroidBitmap_lockPixels(env
, jbitmap
.obj(), &pixels
) < 0) {
83 LOG(ERROR
) << "Error locking java bitmap pixels.";
90 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
,
94 bitmap
.setPixels(pixels
);
96 SkBitmapDevice
device(bitmap
);
97 SkCanvas
canvas(&device
);
98 canvas
.translate(-scroll_x
, -scroll_y
);
99 succeeded
= renderer
.Run(&canvas
);
102 if (AndroidBitmap_unlockPixels(env
, jbitmap
.obj()) < 0) {
103 LOG(ERROR
) << "Error unlocking java bitmap pixels.";
110 class ScopedPixelAccess
{
112 ScopedPixelAccess(JNIEnv
* env
, jobject java_canvas
) {
113 AwDrawSWFunctionTable
* sw_functions
=
114 BrowserViewRenderer::GetAwDrawSWFunctionTable();
115 pixels_
= sw_functions
?
116 sw_functions
->access_pixels(env
, java_canvas
) : NULL
;
118 ~ScopedPixelAccess() {
120 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_
);
122 AwPixelInfo
* pixels() { return pixels_
; }
125 AwPixelInfo
* pixels_
;
127 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess
);
130 bool HardwareEnabled() {
131 static bool g_hw_enabled
= !CommandLine::ForCurrentProcess()->HasSwitch(
132 switches::kDisableWebViewGLMode
);
136 // Provides software rendering functions from the Android glue layer.
137 // Allows preventing extra copies of data when rendering.
138 AwDrawSWFunctionTable
* g_sw_draw_functions
= NULL
;
140 const int64 kFallbackTickTimeoutInMilliseconds
= 20;
143 // Used to calculate memory and resource allocation. Determined experimentally.
144 size_t g_memory_multiplier
= 10;
145 size_t g_num_gralloc_limit
= 150;
146 const size_t kBytesPerPixel
= 4;
147 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
149 class ScopedAllowGL
{
154 static bool IsAllowed() {
155 return BrowserThread::CurrentlyOn(BrowserThread::UI
) && allow_gl
;
159 static bool allow_gl
;
161 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL
);
164 ScopedAllowGL::ScopedAllowGL() {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
170 ScopedAllowGL::~ScopedAllowGL() {
174 bool ScopedAllowGL::allow_gl
= false;
176 base::LazyInstance
<GLViewRendererManager
>::Leaky g_view_renderer_manager
;
178 void RequestProcessGLOnUIThread() {
179 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
180 BrowserThread::PostTask(
181 BrowserThread::UI
, FROM_HERE
, base::Bind(&RequestProcessGLOnUIThread
));
185 InProcessViewRenderer
* renderer
= static_cast<InProcessViewRenderer
*>(
186 g_view_renderer_manager
.Get().GetMostRecentlyDrawn());
187 if (!renderer
|| !renderer
->RequestProcessGL()) {
188 LOG(ERROR
) << "Failed to request GL process. Deadlock likely: "
195 // Called from different threads!
196 static void ScheduleGpuWork() {
197 if (ScopedAllowGL::IsAllowed()) {
198 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
200 RequestProcessGLOnUIThread();
205 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
206 AwDrawSWFunctionTable
* table
) {
207 g_sw_draw_functions
= table
;
208 gpu::InProcessCommandBuffer::SetScheduleCallback(
209 base::Bind(&ScheduleGpuWork
));
213 AwDrawSWFunctionTable
* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
214 return g_sw_draw_functions
;
217 InProcessViewRenderer::InProcessViewRenderer(
218 BrowserViewRenderer::Client
* client
,
219 JavaHelper
* java_helper
,
220 content::WebContents
* web_contents
)
222 java_helper_(java_helper
),
223 web_contents_(web_contents
),
226 view_visible_(false),
227 window_visible_(false),
228 attached_to_window_(false),
230 page_scale_factor_(1.0),
231 on_new_picture_enable_(false),
232 compositor_needs_continuous_invalidate_(false),
233 block_invalidates_(false),
236 hardware_initialized_(false),
237 hardware_failed_(false),
238 last_egl_context_(NULL
),
239 manager_key_(g_view_renderer_manager
.Get().NullKey()) {
240 CHECK(web_contents_
);
241 web_contents_
->SetUserData(kUserDataKey
, new UserData(this));
242 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, this);
244 // Currently the logic in this class relies on |compositor_| remaining NULL
245 // until the DidInitializeCompositor() call, hence it is not set here.
248 InProcessViewRenderer::~InProcessViewRenderer() {
249 CHECK(web_contents_
);
250 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, NULL
);
251 web_contents_
->SetUserData(kUserDataKey
, NULL
);
252 NoLongerExpectsDrawGL();
253 DCHECK(web_contents_
== NULL
); // WebContentsGone should have been called.
256 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
257 GLViewRendererManager
& mru
= g_view_renderer_manager
.Get();
258 if (manager_key_
!= mru
.NullKey()) {
259 mru
.NoLongerExpectsDrawGL(manager_key_
);
260 manager_key_
= mru
.NullKey();
265 InProcessViewRenderer
* InProcessViewRenderer::FromWebContents(
266 content::WebContents
* contents
) {
267 return UserData::GetInstance(contents
);
270 void InProcessViewRenderer::WebContentsGone() {
271 web_contents_
= NULL
;
276 void InProcessViewRenderer::CalculateTileMemoryPolicy() {
277 CommandLine
* cl
= CommandLine::ForCurrentProcess();
278 if (cl
->HasSwitch(switches::kTileMemoryMultiplier
)) {
279 std::string string_value
=
280 cl
->GetSwitchValueASCII(switches::kTileMemoryMultiplier
);
282 if (base::StringToInt(string_value
, &int_value
) &&
283 int_value
>= 2 && int_value
<= 50) {
284 g_memory_multiplier
= int_value
;
288 if (cl
->HasSwitch(switches::kNumGrallocBuffersPerWebview
)) {
289 std::string string_value
=
290 cl
->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview
);
292 if (base::StringToInt(string_value
, &int_value
) &&
293 int_value
>= 50 && int_value
<= 500) {
294 g_num_gralloc_limit
= int_value
;
298 const char kDefaultTileSize
[] = "384";
299 if (!cl
->HasSwitch(switches::kDefaultTileWidth
))
300 cl
->AppendSwitchASCII(switches::kDefaultTileWidth
, kDefaultTileSize
);
302 if (!cl
->HasSwitch(switches::kDefaultTileHeight
))
303 cl
->AppendSwitchASCII(switches::kDefaultTileHeight
, kDefaultTileSize
);
306 bool InProcessViewRenderer::RequestProcessGL() {
307 return client_
->RequestDrawGL(NULL
);
310 void InProcessViewRenderer::TrimMemory(int level
) {
311 // Constants from Android ComponentCallbacks2.
313 TRIM_MEMORY_RUNNING_LOW
= 10,
314 TRIM_MEMORY_UI_HIDDEN
= 20,
315 TRIM_MEMORY_BACKGROUND
= 40,
318 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
319 // it does not indicate memory pressure, but merely that the app is
321 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
325 if (!attached_to_window_
|| !hardware_initialized_
|| !compositor_
)
328 // Do not release resources on view we expect to get DrawGL soon.
329 if (level
< TRIM_MEMORY_BACKGROUND
) {
330 client_
->UpdateGlobalVisibleRect();
331 if (view_visible_
&& window_visible_
&&
332 !cached_global_visible_rect_
.IsEmpty()) {
337 if (!eglGetCurrentContext()) {
342 // Just set the memory limit to 0 and drop all tiles. This will be reset to
343 // normal levels in the next DrawGL call.
344 content::SynchronousCompositorMemoryPolicy policy
;
345 policy
.bytes_limit
= 0;
346 policy
.num_resources_limit
= 0;
347 if (memory_policy_
== policy
)
350 TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
351 ScopedAppGLStateRestore
state_restore(
352 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
353 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
354 ScopedAllowGL allow_gl
;
356 SetMemoryPolicy(policy
);
357 ForceFakeCompositeSW();
360 void InProcessViewRenderer::SetMemoryPolicy(
361 content::SynchronousCompositorMemoryPolicy
& new_policy
) {
362 if (memory_policy_
== new_policy
)
365 memory_policy_
= new_policy
;
366 compositor_
->SetMemoryPolicy(memory_policy_
);
369 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
370 client_
->UpdateGlobalVisibleRect();
373 bool InProcessViewRenderer::OnDraw(jobject java_canvas
,
374 bool is_hardware_canvas
,
375 const gfx::Vector2d
& scroll
,
376 const gfx::Rect
& clip
) {
377 scroll_at_start_of_frame_
= scroll
;
378 if (is_hardware_canvas
&& attached_to_window_
&& HardwareEnabled()) {
379 // We should be performing a hardware draw here. If we don't have the
380 // comositor yet or if RequestDrawGL fails, it means we failed this draw and
381 // thus return false here to clear to background color for this draw.
382 return compositor_
&& client_
->RequestDrawGL(java_canvas
);
384 // Perform a software draw
385 return DrawSWInternal(java_canvas
, clip
);
388 bool InProcessViewRenderer::InitializeHwDraw() {
389 TRACE_EVENT0("android_webview", "InitializeHwDraw");
390 DCHECK(!gl_surface_
);
391 gl_surface_
= new AwGLSurface
;
392 hardware_failed_
= !compositor_
->InitializeHwDraw(gl_surface_
);
393 hardware_initialized_
= true;
395 if (hardware_failed_
)
398 return !hardware_failed_
;
401 void InProcessViewRenderer::DrawGL(AwDrawGLInfo
* draw_info
) {
402 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
404 manager_key_
= g_view_renderer_manager
.Get().DidDrawGL(manager_key_
, this);
406 // We need to watch if the current Android context has changed and enforce
407 // a clean-up in the compositor.
408 EGLContext current_context
= eglGetCurrentContext();
409 if (!current_context
) {
410 TRACE_EVENT_INSTANT0(
411 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD
);
415 ScopedAppGLStateRestore
state_restore(ScopedAppGLStateRestore::MODE_DRAW
);
416 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
417 ScopedAllowGL allow_gl
;
419 if (!attached_to_window_
) {
420 TRACE_EVENT_INSTANT0(
421 "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD
);
425 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
) {
426 TRACE_EVENT_INSTANT0(
427 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD
);
431 if (compositor_
&& !hardware_initialized_
) {
432 if (InitializeHwDraw()) {
433 last_egl_context_
= current_context
;
435 TRACE_EVENT_INSTANT0(
436 "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD
);
437 LOG(ERROR
) << "WebView hardware initialization failed";
442 UpdateCachedGlobalVisibleRect();
443 if (cached_global_visible_rect_
.IsEmpty()) {
444 TRACE_EVENT_INSTANT0("android_webview",
445 "EarlyOut_EmptyVisibleRect",
446 TRACE_EVENT_SCOPE_THREAD
);
450 if (last_egl_context_
!= current_context
) {
451 // TODO(boliu): Handle context lost
452 TRACE_EVENT_INSTANT0(
453 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD
);
457 TRACE_EVENT_INSTANT0(
458 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
462 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
463 // well just to be safe.
464 fallback_tick_
.Cancel();
466 // Update memory budget. This will no-op in compositor if the policy has not
467 // changed since last draw.
468 content::SynchronousCompositorMemoryPolicy policy
;
469 policy
.bytes_limit
= g_memory_multiplier
* kBytesPerPixel
*
470 cached_global_visible_rect_
.width() *
471 cached_global_visible_rect_
.height();
472 // Round up to a multiple of kMemoryAllocationStep.
474 (policy
.bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
475 policy
.num_resources_limit
= g_num_gralloc_limit
;
476 SetMemoryPolicy(policy
);
479 gl_surface_
->SetBackingFrameBufferObject(
480 state_restore
.framebuffer_binding_ext());
482 gfx::Transform transform
;
483 transform
.matrix().setColMajorf(draw_info
->transform
);
484 transform
.Translate(scroll_at_start_of_frame_
.x(),
485 scroll_at_start_of_frame_
.y());
486 gfx::Rect
clip_rect(draw_info
->clip_left
,
488 draw_info
->clip_right
- draw_info
->clip_left
,
489 draw_info
->clip_bottom
- draw_info
->clip_top
);
491 // Assume we always draw the full visible rect if we are drawing into a layer.
492 bool drew_full_visible_rect
= true;
494 gfx::Rect viewport_rect
;
495 if (!draw_info
->is_layer
) {
496 viewport_rect
= cached_global_visible_rect_
;
497 clip_rect
.Intersect(viewport_rect
);
498 drew_full_visible_rect
= clip_rect
.Contains(viewport_rect
);
500 viewport_rect
= clip_rect
;
503 block_invalidates_
= true;
504 // TODO(joth): Check return value.
505 compositor_
->DemandDrawHw(gfx::Size(draw_info
->width
, draw_info
->height
),
509 state_restore
.stencil_enabled());
510 block_invalidates_
= false;
511 gl_surface_
->ResetBackingFrameBufferObject();
513 EnsureContinuousInvalidation(draw_info
, !drew_full_visible_rect
);
516 void InProcessViewRenderer::SetGlobalVisibleRect(
517 const gfx::Rect
& visible_rect
) {
518 cached_global_visible_rect_
= visible_rect
;
521 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas
,
522 const gfx::Rect
& clip
) {
523 if (clip
.IsEmpty()) {
524 TRACE_EVENT_INSTANT0(
525 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD
);
530 TRACE_EVENT_INSTANT0(
531 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
535 return RenderViaAuxilaryBitmapIfNeeded(
538 scroll_at_start_of_frame_
,
540 base::Bind(&InProcessViewRenderer::CompositeSW
,
541 base::Unretained(this)),
546 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
548 BrowserViewRenderer::JavaHelper
* java_helper
,
549 const gfx::Vector2d
& scroll_correction
,
550 const gfx::Rect
& clip
,
551 InProcessViewRenderer::RenderMethod render_source
,
553 TRACE_EVENT0("android_webview",
554 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
556 JNIEnv
* env
= AttachCurrentThread();
557 ScopedPixelAccess
auto_release_pixels(env
, java_canvas
);
558 AwPixelInfo
* pixels
= auto_release_pixels
.pixels();
559 if (pixels
&& pixels
->state
) {
560 skia::RefPtr
<SkCanvas
> canvas
= skia::AdoptRef(
561 SkCanvasStateUtils::CreateFromCanvasState(pixels
->state
));
563 // Workarounds for http://crbug.com/271096: SW draw only supports
564 // translate & scale transforms, and a simple rectangular clip.
565 if (canvas
&& (!canvas
->getTotalClip().isRect() ||
566 (canvas
->getTotalMatrix().getType() &
567 ~(SkMatrix::kTranslate_Mask
| SkMatrix::kScale_Mask
)))) {
571 canvas
->translate(scroll_correction
.x(), scroll_correction
.y());
572 return render_source
.Run(canvas
.get());
576 // Render into an auxiliary bitmap if pixel info is not available.
577 ScopedJavaLocalRef
<jobject
> jcanvas(env
, java_canvas
);
578 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
579 ScopedJavaLocalRef
<jobject
> jbitmap(java_helper
->CreateBitmap(
580 env
, clip
.width(), clip
.height(), jcanvas
, owner_key
));
581 if (!jbitmap
.obj()) {
582 TRACE_EVENT_INSTANT0("android_webview",
583 "EarlyOut_BitmapAllocFail",
584 TRACE_EVENT_SCOPE_THREAD
);
588 if (!RasterizeIntoBitmap(env
, jbitmap
,
589 clip
.x() - scroll_correction
.x(),
590 clip
.y() - scroll_correction
.y(),
592 TRACE_EVENT_INSTANT0("android_webview",
593 "EarlyOut_RasterizeFail",
594 TRACE_EVENT_SCOPE_THREAD
);
598 java_helper
->DrawBitmapIntoCanvas(env
, jbitmap
, jcanvas
,
603 skia::RefPtr
<SkPicture
> InProcessViewRenderer::CapturePicture(int width
,
605 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
607 // Return empty Picture objects for empty SkPictures.
608 skia::RefPtr
<SkPicture
> picture
= skia::AdoptRef(new SkPicture
);
609 if (width
<= 0 || height
<= 0) {
613 // Reset scroll back to the origin, will go back to the old
614 // value when scroll_reset is out of scope.
615 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_dip_
,
618 SkCanvas
* rec_canvas
= picture
->beginRecording(width
, height
, 0);
620 CompositeSW(rec_canvas
);
621 picture
->endRecording();
625 void InProcessViewRenderer::EnableOnNewPicture(bool enabled
) {
626 on_new_picture_enable_
= enabled
;
627 EnsureContinuousInvalidation(NULL
, false);
630 void InProcessViewRenderer::SetIsPaused(bool paused
) {
631 TRACE_EVENT_INSTANT1("android_webview",
632 "InProcessViewRenderer::SetIsPaused",
633 TRACE_EVENT_SCOPE_THREAD
,
637 EnsureContinuousInvalidation(NULL
, false);
640 void InProcessViewRenderer::SetViewVisibility(bool view_visible
) {
641 TRACE_EVENT_INSTANT1("android_webview",
642 "InProcessViewRenderer::SetViewVisibility",
643 TRACE_EVENT_SCOPE_THREAD
,
646 view_visible_
= view_visible
;
649 void InProcessViewRenderer::SetWindowVisibility(bool window_visible
) {
650 TRACE_EVENT_INSTANT1("android_webview",
651 "InProcessViewRenderer::SetWindowVisibility",
652 TRACE_EVENT_SCOPE_THREAD
,
655 window_visible_
= window_visible
;
656 EnsureContinuousInvalidation(NULL
, false);
659 void InProcessViewRenderer::OnSizeChanged(int width
, int height
) {
660 TRACE_EVENT_INSTANT2("android_webview",
661 "InProcessViewRenderer::OnSizeChanged",
662 TRACE_EVENT_SCOPE_THREAD
,
671 void InProcessViewRenderer::OnAttachedToWindow(int width
, int height
) {
672 TRACE_EVENT2("android_webview",
673 "InProcessViewRenderer::OnAttachedToWindow",
678 attached_to_window_
= true;
683 void InProcessViewRenderer::OnDetachedFromWindow() {
684 TRACE_EVENT0("android_webview",
685 "InProcessViewRenderer::OnDetachedFromWindow");
687 NoLongerExpectsDrawGL();
688 if (hardware_initialized_
) {
691 ScopedAppGLStateRestore
state_restore(
692 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
);
693 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
694 ScopedAllowGL allow_gl
;
695 compositor_
->ReleaseHwDraw();
696 hardware_initialized_
= false;
700 attached_to_window_
= false;
703 bool InProcessViewRenderer::IsAttachedToWindow() {
704 return attached_to_window_
;
707 bool InProcessViewRenderer::IsVisible() {
708 // Ignore |window_visible_| if |attached_to_window_| is false.
709 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
712 gfx::Rect
InProcessViewRenderer::GetScreenRect() {
713 return gfx::Rect(client_
->GetLocationOnScreen(), gfx::Size(width_
, height_
));
716 void InProcessViewRenderer::DidInitializeCompositor(
717 content::SynchronousCompositor
* compositor
) {
718 TRACE_EVENT0("android_webview",
719 "InProcessViewRenderer::DidInitializeCompositor");
720 DCHECK(compositor
&& compositor_
== NULL
);
721 compositor_
= compositor
;
722 hardware_initialized_
= false;
723 hardware_failed_
= false;
726 void InProcessViewRenderer::DidDestroyCompositor(
727 content::SynchronousCompositor
* compositor
) {
728 TRACE_EVENT0("android_webview",
729 "InProcessViewRenderer::DidDestroyCompositor");
730 DCHECK(compositor_
== compositor
);
732 // This can fail if Apps call destroy while the webview is still attached
733 // to the view tree. This is an illegal operation that will lead to leaks.
734 // Log for now. Consider a proper fix if this becomes a problem.
735 LOG_IF(ERROR
, hardware_initialized_
)
736 << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
740 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate
) {
741 if (compositor_needs_continuous_invalidate_
== invalidate
)
744 TRACE_EVENT_INSTANT1("android_webview",
745 "InProcessViewRenderer::SetContinuousInvalidate",
746 TRACE_EVENT_SCOPE_THREAD
,
749 compositor_needs_continuous_invalidate_
= invalidate
;
750 EnsureContinuousInvalidation(NULL
, false);
753 void InProcessViewRenderer::SetDipScale(float dip_scale
) {
754 dip_scale_
= dip_scale
;
755 CHECK(dip_scale_
> 0);
758 gfx::Vector2d
InProcessViewRenderer::max_scroll_offset() const {
759 DCHECK_GT(dip_scale_
, 0);
760 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
761 max_scroll_offset_dip_
, dip_scale_
* page_scale_factor_
));
764 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset
) {
765 gfx::Vector2d max_offset
= max_scroll_offset();
766 gfx::Vector2dF scroll_offset_dip
;
767 // To preserve the invariant that scrolling to the maximum physical pixel
768 // value also scrolls to the maximum dip pixel value we transform the physical
769 // offset into the dip offset by using a proportion (instead of dividing by
770 // dip_scale * page_scale_factor).
771 if (max_offset
.x()) {
772 scroll_offset_dip
.set_x((scroll_offset
.x() * max_scroll_offset_dip_
.x()) /
775 if (max_offset
.y()) {
776 scroll_offset_dip
.set_y((scroll_offset
.y() * max_scroll_offset_dip_
.y()) /
780 DCHECK_LE(0, scroll_offset_dip
.x());
781 DCHECK_LE(0, scroll_offset_dip
.y());
782 DCHECK_LE(scroll_offset_dip
.x(), max_scroll_offset_dip_
.x());
783 DCHECK_LE(scroll_offset_dip
.y(), max_scroll_offset_dip_
.y());
785 if (scroll_offset_dip_
== scroll_offset_dip
)
788 scroll_offset_dip_
= scroll_offset_dip
;
791 compositor_
->DidChangeRootLayerScrollOffset();
794 void InProcessViewRenderer::DidUpdateContent() {
795 if (on_new_picture_enable_
)
796 client_
->OnNewPicture();
799 void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
800 gfx::Vector2dF new_value_dip
) {
801 DCHECK_GT(dip_scale_
, 0);
803 max_scroll_offset_dip_
= new_value_dip
;
804 DCHECK_LE(0, max_scroll_offset_dip_
.x());
805 DCHECK_LE(0, max_scroll_offset_dip_
.y());
807 client_
->SetMaxContainerViewScrollOffset(max_scroll_offset());
810 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
811 gfx::Vector2dF scroll_offset_dip
) {
812 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
813 // DrawGl when http://crbug.com/249972 is fixed.
814 if (scroll_offset_dip_
== scroll_offset_dip
)
817 scroll_offset_dip_
= scroll_offset_dip
;
819 gfx::Vector2d max_offset
= max_scroll_offset();
820 gfx::Vector2d scroll_offset
;
821 // For an explanation as to why this is done this way see the comment in
822 // InProcessViewRenderer::ScrollTo.
823 if (max_scroll_offset_dip_
.x()) {
824 scroll_offset
.set_x((scroll_offset_dip
.x() * max_offset
.x()) /
825 max_scroll_offset_dip_
.x());
828 if (max_scroll_offset_dip_
.y()) {
829 scroll_offset
.set_y((scroll_offset_dip
.y() * max_offset
.y()) /
830 max_scroll_offset_dip_
.y());
833 DCHECK(0 <= scroll_offset
.x());
834 DCHECK(0 <= scroll_offset
.y());
835 DCHECK(scroll_offset
.x() <= max_offset
.x());
836 DCHECK(scroll_offset
.y() <= max_offset
.y());
838 client_
->ScrollContainerViewTo(scroll_offset
);
841 gfx::Vector2dF
InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
842 return scroll_offset_dip_
;
845 bool InProcessViewRenderer::IsExternalFlingActive() const {
846 return client_
->IsFlingActive();
849 void InProcessViewRenderer::SetRootLayerPageScaleFactor(
850 float page_scale_factor
) {
851 page_scale_factor_
= page_scale_factor
;
852 DCHECK_GT(page_scale_factor_
, 0);
853 client_
->SetPageScaleFactor(page_scale_factor
);
856 void InProcessViewRenderer::SetRootLayerScrollableSize(
857 gfx::SizeF scrollable_size
) {
858 client_
->SetContentsSize(scrollable_size
);
861 void InProcessViewRenderer::DidOverscroll(
862 gfx::Vector2dF accumulated_overscroll
,
863 gfx::Vector2dF latest_overscroll_delta
,
864 gfx::Vector2dF current_fling_velocity
) {
865 DCHECK(current_fling_velocity
.IsZero());
866 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
867 if (accumulated_overscroll
== latest_overscroll_delta
)
868 overscroll_rounding_error_
= gfx::Vector2dF();
869 gfx::Vector2dF scaled_overscroll_delta
=
870 gfx::ScaleVector2d(latest_overscroll_delta
, physical_pixel_scale
);
871 gfx::Vector2d rounded_overscroll_delta
= gfx::ToRoundedVector2d(
872 scaled_overscroll_delta
+ overscroll_rounding_error_
);
873 overscroll_rounding_error_
=
874 scaled_overscroll_delta
- rounded_overscroll_delta
;
875 client_
->DidOverscroll(rounded_overscroll_delta
);
878 void InProcessViewRenderer::EnsureContinuousInvalidation(
879 AwDrawGLInfo
* draw_info
,
880 bool invalidate_ignore_compositor
) {
881 // This method should be called again when any of these conditions change.
882 bool need_invalidate
=
883 compositor_needs_continuous_invalidate_
|| invalidate_ignore_compositor
;
884 if (!need_invalidate
|| block_invalidates_
)
888 draw_info
->dirty_left
= cached_global_visible_rect_
.x();
889 draw_info
->dirty_top
= cached_global_visible_rect_
.y();
890 draw_info
->dirty_right
= cached_global_visible_rect_
.right();
891 draw_info
->dirty_bottom
= cached_global_visible_rect_
.bottom();
892 draw_info
->status_mask
|= AwDrawGLInfo::kStatusMaskDraw
;
894 client_
->PostInvalidate();
897 bool throttle_fallback_tick
= (is_paused_
&& !on_new_picture_enable_
) ||
898 (attached_to_window_
&& !window_visible_
);
899 if (throttle_fallback_tick
)
902 block_invalidates_
= compositor_needs_continuous_invalidate_
;
904 // Unretained here is safe because the callback is cancelled when
905 // |fallback_tick_| is destroyed.
906 fallback_tick_
.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired
,
907 base::Unretained(this)));
909 // No need to reschedule fallback tick if compositor does not need to be
910 // ticked. This can happen if this is reached because
911 // invalidate_ignore_compositor is true.
912 if (compositor_needs_continuous_invalidate_
) {
913 BrowserThread::PostDelayedTask(
916 fallback_tick_
.callback(),
917 base::TimeDelta::FromMilliseconds(
918 kFallbackTickTimeoutInMilliseconds
));
922 void InProcessViewRenderer::FallbackTickFired() {
923 TRACE_EVENT1("android_webview",
924 "InProcessViewRenderer::FallbackTickFired",
925 "compositor_needs_continuous_invalidate_",
926 compositor_needs_continuous_invalidate_
);
928 // This should only be called if OnDraw or DrawGL did not come in time, which
929 // means block_invalidates_ must still be true.
930 DCHECK(block_invalidates_
);
931 if (compositor_needs_continuous_invalidate_
&& compositor_
)
932 ForceFakeCompositeSW();
935 void InProcessViewRenderer::ForceFakeCompositeSW() {
937 SkBitmapDevice
device(SkBitmap::kARGB_8888_Config
, 1, 1);
938 SkCanvas
canvas(&device
);
939 CompositeSW(&canvas
);
942 bool InProcessViewRenderer::CompositeSW(SkCanvas
* canvas
) {
945 fallback_tick_
.Cancel();
946 block_invalidates_
= true;
947 bool result
= compositor_
->DemandDrawSw(canvas
);
948 block_invalidates_
= false;
949 EnsureContinuousInvalidation(NULL
, false);
953 std::string
InProcessViewRenderer::ToString(AwDrawGLInfo
* draw_info
) const {
955 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
956 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
957 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
958 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
959 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
960 base::StringAppendF(&str
,
961 "compositor_needs_continuous_invalidate: %d ",
962 compositor_needs_continuous_invalidate_
);
963 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
964 base::StringAppendF(&str
, "view width height: [%d %d] ", width_
, height_
);
965 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
966 base::StringAppendF(&str
, "hardware_initialized: %d ", hardware_initialized_
);
967 base::StringAppendF(&str
, "hardware_failed: %d ", hardware_failed_
);
968 base::StringAppendF(&str
,
969 "global visible rect: %s ",
970 cached_global_visible_rect_
.ToString().c_str());
971 base::StringAppendF(&str
,
972 "scroll_at_start_of_frame: %s ",
973 scroll_at_start_of_frame_
.ToString().c_str());
975 &str
, "scroll_offset_dip: %s ", scroll_offset_dip_
.ToString().c_str());
976 base::StringAppendF(&str
,
977 "overscroll_rounding_error_: %s ",
978 overscroll_rounding_error_
.ToString().c_str());
980 &str
, "on_new_picture_enable: %d ", on_new_picture_enable_
);
982 base::StringAppendF(&str
,
983 "clip left top right bottom: [%d %d %d %d] ",
984 draw_info
->clip_left
,
986 draw_info
->clip_right
,
987 draw_info
->clip_bottom
);
988 base::StringAppendF(&str
,
989 "surface width height: [%d %d] ",
992 base::StringAppendF(&str
, "is_layer: %d ", draw_info
->is_layer
);
997 } // namespace android_webview