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/stringprintf.h"
21 #include "content/public/browser/android/synchronous_compositor.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "gpu/command_buffer/service/in_process_command_buffer.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "third_party/skia/include/core/SkCanvas.h"
27 #include "third_party/skia/include/core/SkDevice.h"
28 #include "third_party/skia/include/core/SkGraphics.h"
29 #include "third_party/skia/include/core/SkPicture.h"
30 #include "ui/gfx/skia_util.h"
31 #include "ui/gfx/transform.h"
32 #include "ui/gfx/vector2d_conversions.h"
33 #include "ui/gfx/vector2d_f.h"
35 using base::android::AttachCurrentThread
;
36 using base::android::JavaRef
;
37 using base::android::ScopedJavaLocalRef
;
38 using content::BrowserThread
;
40 namespace android_webview
{
45 const void* kUserDataKey
= &kUserDataKey
;
47 class UserData
: public content::WebContents::Data
{
49 UserData(InProcessViewRenderer
* ptr
) : instance_(ptr
) {}
51 instance_
->WebContentsGone();
54 static InProcessViewRenderer
* GetInstance(content::WebContents
* contents
) {
57 UserData
* data
= reinterpret_cast<UserData
*>(
58 contents
->GetUserData(kUserDataKey
));
59 return data
? data
->instance_
: NULL
;
63 InProcessViewRenderer
* instance_
;
66 bool RasterizeIntoBitmap(JNIEnv
* env
,
67 const JavaRef
<jobject
>& jbitmap
,
70 const InProcessViewRenderer::RenderMethod
& renderer
) {
71 DCHECK(jbitmap
.obj());
73 AndroidBitmapInfo bitmap_info
;
74 if (AndroidBitmap_getInfo(env
, jbitmap
.obj(), &bitmap_info
) < 0) {
75 LOG(ERROR
) << "Error getting java bitmap info.";
80 if (AndroidBitmap_lockPixels(env
, jbitmap
.obj(), &pixels
) < 0) {
81 LOG(ERROR
) << "Error locking java bitmap pixels.";
88 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
,
92 bitmap
.setPixels(pixels
);
94 SkDevice
device(bitmap
);
95 SkCanvas
canvas(&device
);
96 canvas
.translate(-scroll_x
, -scroll_y
);
97 succeeded
= renderer
.Run(&canvas
);
100 if (AndroidBitmap_unlockPixels(env
, jbitmap
.obj()) < 0) {
101 LOG(ERROR
) << "Error unlocking java bitmap pixels.";
108 bool RenderPictureToCanvas(SkPicture
* picture
, SkCanvas
* canvas
) {
109 canvas
->drawPicture(*picture
);
113 class ScopedPixelAccess
{
115 ScopedPixelAccess(JNIEnv
* env
, jobject java_canvas
) {
116 AwDrawSWFunctionTable
* sw_functions
=
117 BrowserViewRenderer::GetAwDrawSWFunctionTable();
118 pixels_
= sw_functions
?
119 sw_functions
->access_pixels(env
, java_canvas
) : NULL
;
121 ~ScopedPixelAccess() {
123 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_
);
125 AwPixelInfo
* pixels() { return pixels_
; }
128 AwPixelInfo
* pixels_
;
130 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess
);
133 bool HardwareEnabled() {
134 static bool g_hw_enabled
= !CommandLine::ForCurrentProcess()->HasSwitch(
135 switches::kDisableWebViewGLMode
);
139 // Provides software rendering functions from the Android glue layer.
140 // Allows preventing extra copies of data when rendering.
141 AwDrawSWFunctionTable
* g_sw_draw_functions
= NULL
;
143 const int64 kFallbackTickTimeoutInMilliseconds
= 20;
145 class ScopedAllowGL
{
150 static bool IsAllowed() {
151 return BrowserThread::CurrentlyOn(BrowserThread::UI
) && allow_gl
;
155 static bool allow_gl
;
157 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL
);
160 ScopedAllowGL::ScopedAllowGL() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
166 ScopedAllowGL::~ScopedAllowGL() {
170 bool ScopedAllowGL::allow_gl
= false;
172 base::LazyInstance
<GLViewRendererManager
>::Leaky g_view_renderer_manager
;
176 // Called from different threads!
177 static void ScheduleGpuWork() {
178 if (ScopedAllowGL::IsAllowed()) {
179 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
181 InProcessViewRenderer
* renderer
= static_cast<InProcessViewRenderer
*>(
182 g_view_renderer_manager
.Get().GetMostRecentlyDrawn());
183 if (!renderer
|| !renderer
->RequestProcessGL()) {
184 LOG(ERROR
) << "Failed to request DrawGL. Probably going to deadlock.";
190 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
191 AwDrawSWFunctionTable
* table
) {
192 g_sw_draw_functions
= table
;
193 gpu::InProcessCommandBuffer::SetScheduleCallback(
194 base::Bind(&ScheduleGpuWork
));
198 AwDrawSWFunctionTable
* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
199 return g_sw_draw_functions
;
202 InProcessViewRenderer::InProcessViewRenderer(
203 BrowserViewRenderer::Client
* client
,
204 JavaHelper
* java_helper
,
205 content::WebContents
* web_contents
)
207 java_helper_(java_helper
),
208 web_contents_(web_contents
),
211 view_visible_(false),
212 window_visible_(false),
213 attached_to_window_(false),
215 page_scale_factor_(1.0),
216 on_new_picture_enable_(false),
217 compositor_needs_continuous_invalidate_(false),
218 block_invalidates_(false),
221 hardware_initialized_(false),
222 hardware_failed_(false),
223 last_egl_context_(NULL
),
224 manager_key_(g_view_renderer_manager
.Get().NullKey()) {
225 CHECK(web_contents_
);
226 web_contents_
->SetUserData(kUserDataKey
, new UserData(this));
227 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, this);
229 // Currently the logic in this class relies on |compositor_| remaining NULL
230 // until the DidInitializeCompositor() call, hence it is not set here.
233 InProcessViewRenderer::~InProcessViewRenderer() {
234 CHECK(web_contents_
);
235 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, NULL
);
236 web_contents_
->SetUserData(kUserDataKey
, NULL
);
237 NoLongerExpectsDrawGL();
238 DCHECK(web_contents_
== NULL
); // WebContentsGone should have been called.
242 // TODO(boliu): Should also call this when we know for sure we are no longer,
243 // for example, when visible rect becomes 0.
244 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
245 GLViewRendererManager
& mru
= g_view_renderer_manager
.Get();
246 if (manager_key_
!= mru
.NullKey()) {
247 mru
.NoLongerExpectsDrawGL(manager_key_
);
248 manager_key_
= mru
.NullKey();
250 // TODO(boliu): If this is the first one and there are GL pending,
251 // requestDrawGL on next one.
252 // TODO(boliu): If this is the last one, lose all global contexts.
257 InProcessViewRenderer
* InProcessViewRenderer::FromWebContents(
258 content::WebContents
* contents
) {
259 return UserData::GetInstance(contents
);
262 void InProcessViewRenderer::WebContentsGone() {
263 web_contents_
= NULL
;
267 bool InProcessViewRenderer::RequestProcessGL() {
268 return client_
->RequestDrawGL(NULL
);
271 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
272 client_
->UpdateGlobalVisibleRect();
275 bool InProcessViewRenderer::OnDraw(jobject java_canvas
,
276 bool is_hardware_canvas
,
277 const gfx::Vector2d
& scroll
,
278 const gfx::Rect
& clip
) {
279 scroll_at_start_of_frame_
= scroll
;
280 if (is_hardware_canvas
&& attached_to_window_
&& HardwareEnabled()) {
281 // We should be performing a hardware draw here. If we don't have the
282 // comositor yet or if RequestDrawGL fails, it means we failed this draw and
283 // thus return false here to clear to background color for this draw.
284 return compositor_
&& client_
->RequestDrawGL(java_canvas
);
286 // Perform a software draw
287 block_invalidates_
= true;
288 bool result
= DrawSWInternal(java_canvas
, clip
);
289 block_invalidates_
= false;
290 EnsureContinuousInvalidation(NULL
, false);
294 bool InProcessViewRenderer::InitializeHwDraw() {
295 TRACE_EVENT0("android_webview", "InitializeHwDraw");
296 DCHECK(!gl_surface_
);
297 gl_surface_
= new AwGLSurface
;
298 hardware_failed_
= !compositor_
->InitializeHwDraw(gl_surface_
);
299 hardware_initialized_
= true;
301 if (hardware_failed_
)
304 return !hardware_failed_
;
307 void InProcessViewRenderer::DrawGL(AwDrawGLInfo
* draw_info
) {
308 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
310 manager_key_
= g_view_renderer_manager
.Get().DidDrawGL(manager_key_
, this);
312 // We need to watch if the current Android context has changed and enforce
313 // a clean-up in the compositor.
314 EGLContext current_context
= eglGetCurrentContext();
315 if (!current_context
) {
316 TRACE_EVENT_INSTANT0(
317 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD
);
321 ScopedAppGLStateRestore
state_restore(ScopedAppGLStateRestore::MODE_DRAW
);
322 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
323 ScopedAllowGL allow_gl
;
325 if (attached_to_window_
&& compositor_
&& !hardware_initialized_
) {
326 if (InitializeHwDraw()) {
327 last_egl_context_
= current_context
;
333 if (draw_info
->mode
== AwDrawGLInfo::kModeProcess
) {
334 TRACE_EVENT_INSTANT0(
335 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD
);
339 UpdateCachedGlobalVisibleRect();
340 if (cached_global_visible_rect_
.IsEmpty()) {
341 TRACE_EVENT_INSTANT0("android_webview",
342 "EarlyOut_EmptyVisibleRect",
343 TRACE_EVENT_SCOPE_THREAD
);
347 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
348 // well just to be safe.
349 fallback_tick_
.Cancel();
351 if (last_egl_context_
!= current_context
) {
352 // TODO(boliu): Handle context lost
353 TRACE_EVENT_INSTANT0(
354 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD
);
358 TRACE_EVENT_INSTANT0(
359 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
364 gl_surface_
->SetBackingFrameBufferObject(
365 state_restore
.framebuffer_binding_ext());
367 gfx::Transform transform
;
368 transform
.matrix().setColMajorf(draw_info
->transform
);
369 transform
.Translate(scroll_at_start_of_frame_
.x(),
370 scroll_at_start_of_frame_
.y());
371 gfx::Rect
clip_rect(draw_info
->clip_left
,
373 draw_info
->clip_right
- draw_info
->clip_left
,
374 draw_info
->clip_bottom
- draw_info
->clip_top
);
376 // Assume we always draw the full visible rect if we are drawing into a layer.
377 bool drew_full_visible_rect
= true;
379 if (!draw_info
->is_layer
) {
380 clip_rect
.Intersect(cached_global_visible_rect_
);
381 drew_full_visible_rect
= clip_rect
.Contains(cached_global_visible_rect_
);
384 block_invalidates_
= true;
385 // TODO(joth): Check return value.
386 compositor_
->DemandDrawHw(gfx::Size(draw_info
->width
, draw_info
->height
),
389 state_restore
.stencil_enabled());
390 block_invalidates_
= false;
391 gl_surface_
->ResetBackingFrameBufferObject();
393 EnsureContinuousInvalidation(draw_info
, !drew_full_visible_rect
);
396 void InProcessViewRenderer::SetGlobalVisibleRect(
397 const gfx::Rect
& visible_rect
) {
398 cached_global_visible_rect_
= visible_rect
;
401 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas
,
402 const gfx::Rect
& clip
) {
403 fallback_tick_
.Cancel();
405 if (clip
.IsEmpty()) {
406 TRACE_EVENT_INSTANT0(
407 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD
);
412 TRACE_EVENT_INSTANT0(
413 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
417 return RenderViaAuxilaryBitmapIfNeeded(
420 scroll_at_start_of_frame_
,
422 base::Bind(&InProcessViewRenderer::CompositeSW
,
423 base::Unretained(this)),
428 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
430 BrowserViewRenderer::JavaHelper
* java_helper
,
431 const gfx::Vector2d
& scroll_correction
,
432 const gfx::Rect
& clip
,
433 InProcessViewRenderer::RenderMethod render_source
,
435 TRACE_EVENT0("android_webview",
436 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
438 JNIEnv
* env
= AttachCurrentThread();
439 ScopedPixelAccess
auto_release_pixels(env
, java_canvas
);
440 AwPixelInfo
* pixels
= auto_release_pixels
.pixels();
442 SkBitmap::Config
config(SkBitmap::kNo_Config
);
444 switch (pixels
->config
) {
445 case AwConfig_ARGB_8888
:
446 config
= SkBitmap::kARGB_8888_Config
;
448 case AwConfig_RGB_565
:
449 config
= SkBitmap::kRGB_565_Config
;
453 for (int i
= 0; i
< 9; i
++) {
454 matrix
.set(i
, pixels
->matrix
[i
]);
456 // Workaround for http://crbug.com/271096: SW draw only supports
457 // translate & scale transforms.
458 if (matrix
.getType() & ~(SkMatrix::kTranslate_Mask
| SkMatrix::kScale_Mask
))
459 config
= SkBitmap::kNo_Config
;
462 if (config
== SkBitmap::kNo_Config
) {
463 // Render into an auxiliary bitmap if pixel info is not available.
464 ScopedJavaLocalRef
<jobject
> jcanvas(env
, java_canvas
);
465 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
466 ScopedJavaLocalRef
<jobject
> jbitmap(java_helper
->CreateBitmap(
467 env
, clip
.width(), clip
.height(), jcanvas
, owner_key
));
468 if (!jbitmap
.obj()) {
469 TRACE_EVENT_INSTANT0("android_webview",
470 "EarlyOut_BitmapAllocFail",
471 TRACE_EVENT_SCOPE_THREAD
);
475 if (!RasterizeIntoBitmap(env
, jbitmap
,
476 clip
.x() - scroll_correction
.x(),
477 clip
.y() - scroll_correction
.y(),
479 TRACE_EVENT_INSTANT0("android_webview",
480 "EarlyOut_RasterizeFail",
481 TRACE_EVENT_SCOPE_THREAD
);
485 java_helper
->DrawBitmapIntoCanvas(env
, jbitmap
, jcanvas
,
490 // Draw in a SkCanvas built over the pixel information.
492 bitmap
.setConfig(config
,
496 bitmap
.setPixels(pixels
->pixels
);
497 SkDevice
device(bitmap
);
498 SkCanvas
canvas(&device
);
499 canvas
.setMatrix(matrix
);
501 if (pixels
->clip_rect_count
) {
503 for (int i
= 0; i
< pixels
->clip_rect_count
; ++i
) {
504 clip
.op(SkIRect::MakeXYWH(pixels
->clip_rects
[i
+ 0],
505 pixels
->clip_rects
[i
+ 1],
506 pixels
->clip_rects
[i
+ 2],
507 pixels
->clip_rects
[i
+ 3]),
508 SkRegion::kUnion_Op
);
510 canvas
.setClipRegion(clip
);
513 canvas
.translate(scroll_correction
.x(),
514 scroll_correction
.y());
516 return render_source
.Run(&canvas
);
519 skia::RefPtr
<SkPicture
> InProcessViewRenderer::CapturePicture(int width
,
521 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
523 // Return empty Picture objects for empty SkPictures.
524 skia::RefPtr
<SkPicture
> picture
= skia::AdoptRef(new SkPicture
);
525 if (width
<= 0 || height
<= 0) {
529 // Reset scroll back to the origin, will go back to the old
530 // value when scroll_reset is out of scope.
531 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_css_
,
534 SkCanvas
* rec_canvas
= picture
->beginRecording(width
, height
, 0);
536 CompositeSW(rec_canvas
);
537 picture
->endRecording();
541 void InProcessViewRenderer::EnableOnNewPicture(bool enabled
) {
542 on_new_picture_enable_
= enabled
;
545 void InProcessViewRenderer::SetIsPaused(bool paused
) {
546 TRACE_EVENT_INSTANT1("android_webview",
547 "InProcessViewRenderer::SetIsPaused",
548 TRACE_EVENT_SCOPE_THREAD
,
552 EnsureContinuousInvalidation(NULL
, false);
555 void InProcessViewRenderer::SetViewVisibility(bool view_visible
) {
556 TRACE_EVENT_INSTANT1("android_webview",
557 "InProcessViewRenderer::SetViewVisibility",
558 TRACE_EVENT_SCOPE_THREAD
,
561 view_visible_
= view_visible
;
564 void InProcessViewRenderer::SetWindowVisibility(bool window_visible
) {
565 TRACE_EVENT_INSTANT1("android_webview",
566 "InProcessViewRenderer::SetWindowVisibility",
567 TRACE_EVENT_SCOPE_THREAD
,
570 window_visible_
= window_visible
;
571 EnsureContinuousInvalidation(NULL
, false);
574 void InProcessViewRenderer::OnSizeChanged(int width
, int height
) {
575 TRACE_EVENT_INSTANT2("android_webview",
576 "InProcessViewRenderer::OnSizeChanged",
577 TRACE_EVENT_SCOPE_THREAD
,
586 void InProcessViewRenderer::OnAttachedToWindow(int width
, int height
) {
587 TRACE_EVENT2("android_webview",
588 "InProcessViewRenderer::OnAttachedToWindow",
593 attached_to_window_
= true;
598 void InProcessViewRenderer::OnDetachedFromWindow() {
599 TRACE_EVENT0("android_webview",
600 "InProcessViewRenderer::OnDetachedFromWindow");
602 NoLongerExpectsDrawGL();
603 if (hardware_initialized_
) {
606 ScopedAppGLStateRestore
state_restore(
607 ScopedAppGLStateRestore::MODE_DETACH_FROM_WINDOW
);
608 gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
609 ScopedAllowGL allow_gl
;
610 compositor_
->ReleaseHwDraw();
611 hardware_initialized_
= false;
615 attached_to_window_
= false;
618 bool InProcessViewRenderer::IsAttachedToWindow() {
619 return attached_to_window_
;
622 bool InProcessViewRenderer::IsVisible() {
623 // Ignore |window_visible_| if |attached_to_window_| is false.
624 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
627 gfx::Rect
InProcessViewRenderer::GetScreenRect() {
628 return gfx::Rect(client_
->GetLocationOnScreen(), gfx::Size(width_
, height_
));
631 void InProcessViewRenderer::DidInitializeCompositor(
632 content::SynchronousCompositor
* compositor
) {
633 TRACE_EVENT0("android_webview",
634 "InProcessViewRenderer::DidInitializeCompositor");
635 DCHECK(compositor
&& compositor_
== NULL
);
636 compositor_
= compositor
;
637 hardware_initialized_
= false;
638 hardware_failed_
= false;
641 void InProcessViewRenderer::DidDestroyCompositor(
642 content::SynchronousCompositor
* compositor
) {
643 TRACE_EVENT0("android_webview",
644 "InProcessViewRenderer::DidDestroyCompositor");
645 DCHECK(compositor_
== compositor
);
647 // This can fail if Apps call destroy while the webview is still attached
648 // to the view tree. This is an illegal operation that will lead to leaks.
649 // Log for now. Consider a proper fix if this becomes a problem.
650 LOG_IF(ERROR
, hardware_initialized_
)
651 << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
655 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate
) {
656 if (compositor_needs_continuous_invalidate_
== invalidate
)
659 TRACE_EVENT_INSTANT1("android_webview",
660 "InProcessViewRenderer::SetContinuousInvalidate",
661 TRACE_EVENT_SCOPE_THREAD
,
664 compositor_needs_continuous_invalidate_
= invalidate
;
665 EnsureContinuousInvalidation(NULL
, false);
668 void InProcessViewRenderer::SetDipScale(float dip_scale
) {
669 dip_scale_
= dip_scale
;
670 CHECK(dip_scale_
> 0);
673 void InProcessViewRenderer::SetPageScaleFactor(float page_scale_factor
) {
674 page_scale_factor_
= page_scale_factor
;
675 CHECK(page_scale_factor_
> 0);
678 void InProcessViewRenderer::ScrollTo(gfx::Vector2d new_value
) {
679 DCHECK(dip_scale_
> 0);
680 // In general we don't guarantee that the scroll offset transforms are
681 // symmetrical. That is if scrolling from JS to offset1 results in a native
682 // offset2 then scrolling from UI to offset2 results in JS being scrolled to
684 // The reason we explicitly do rounding here is that it seems to yeld the
685 // most stabile transformation.
686 gfx::Vector2dF new_value_css
= gfx::ToRoundedVector2d(
687 gfx::ScaleVector2d(new_value
, 1.0f
/ (dip_scale_
* page_scale_factor_
)));
689 // It's possible that more than one set of unique physical coordinates maps
690 // to the same set of CSS coordinates which means we can't reliably early-out
691 // earlier in the call stack.
692 if (scroll_offset_css_
== new_value_css
)
695 scroll_offset_css_
= new_value_css
;
698 compositor_
->DidChangeRootLayerScrollOffset();
701 void InProcessViewRenderer::DidUpdateContent() {
702 if (on_new_picture_enable_
)
703 client_
->OnNewPicture();
706 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
707 gfx::Vector2dF new_value_css
) {
708 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
709 // DrawGl when http://crbug.com/249972 is fixed.
710 if (scroll_offset_css_
== new_value_css
)
713 scroll_offset_css_
= new_value_css
;
715 DCHECK(dip_scale_
> 0);
716 DCHECK(page_scale_factor_
> 0);
718 gfx::Vector2d scroll_offset
= gfx::ToRoundedVector2d(
719 gfx::ScaleVector2d(new_value_css
, dip_scale_
* page_scale_factor_
));
721 client_
->ScrollContainerViewTo(scroll_offset
);
724 gfx::Vector2dF
InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
725 return scroll_offset_css_
;
728 void InProcessViewRenderer::DidOverscroll(
729 gfx::Vector2dF latest_overscroll_delta
,
730 gfx::Vector2dF current_fling_velocity
) {
731 // TODO(mkosiba): Enable this once flinging is handled entirely Java-side.
732 // DCHECK(current_fling_velocity.IsZero());
733 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
734 gfx::Vector2dF scaled_overscroll_delta
= gfx::ScaleVector2d(
735 latest_overscroll_delta
+ overscroll_rounding_error_
,
736 physical_pixel_scale
);
737 gfx::Vector2d rounded_overscroll_delta
=
738 gfx::ToRoundedVector2d(scaled_overscroll_delta
);
739 overscroll_rounding_error_
=
740 scaled_overscroll_delta
- rounded_overscroll_delta
;
741 client_
->DidOverscroll(rounded_overscroll_delta
);
744 void InProcessViewRenderer::EnsureContinuousInvalidation(
745 AwDrawGLInfo
* draw_info
,
746 bool invalidate_ignore_compositor
) {
747 // This method should be called again when any of these conditions change.
748 bool need_invalidate
=
749 compositor_needs_continuous_invalidate_
|| invalidate_ignore_compositor
;
750 bool throttle
= is_paused_
|| (attached_to_window_
&& !window_visible_
);
751 if (!need_invalidate
|| block_invalidates_
|| throttle
)
755 draw_info
->dirty_left
= cached_global_visible_rect_
.x();
756 draw_info
->dirty_top
= cached_global_visible_rect_
.y();
757 draw_info
->dirty_right
= cached_global_visible_rect_
.right();
758 draw_info
->dirty_bottom
= cached_global_visible_rect_
.bottom();
759 draw_info
->status_mask
|= AwDrawGLInfo::kStatusMaskDraw
;
761 client_
->PostInvalidate();
764 block_invalidates_
= true;
766 // Unretained here is safe because the callback is cancelled when
767 // |fallback_tick_| is destroyed.
768 fallback_tick_
.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired
,
769 base::Unretained(this)));
771 // No need to reschedule fallback tick if compositor does not need to be
772 // ticked. This can happen if this is reached because
773 // invalidate_ignore_compositor is true.
774 if (compositor_needs_continuous_invalidate_
) {
775 base::MessageLoop::current()->PostDelayedTask(
777 fallback_tick_
.callback(),
778 base::TimeDelta::FromMilliseconds(
779 kFallbackTickTimeoutInMilliseconds
));
783 void InProcessViewRenderer::FallbackTickFired() {
784 TRACE_EVENT1("android_webview",
785 "InProcessViewRenderer::FallbackTickFired",
786 "compositor_needs_continuous_invalidate_",
787 compositor_needs_continuous_invalidate_
);
789 // This should only be called if OnDraw or DrawGL did not come in time, which
790 // means block_invalidates_ must still be true.
791 DCHECK(block_invalidates_
);
792 if (compositor_needs_continuous_invalidate_
&& compositor_
) {
793 SkDevice
device(SkBitmap::kARGB_8888_Config
, 1, 1);
794 SkCanvas
canvas(&device
);
795 block_invalidates_
= true;
796 CompositeSW(&canvas
);
798 block_invalidates_
= false;
799 EnsureContinuousInvalidation(NULL
, false);
802 bool InProcessViewRenderer::CompositeSW(SkCanvas
* canvas
) {
804 return compositor_
->DemandDrawSw(canvas
);
807 std::string
InProcessViewRenderer::ToString(AwDrawGLInfo
* draw_info
) const {
809 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
810 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
811 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
812 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
813 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
814 base::StringAppendF(&str
,
815 "compositor_needs_continuous_invalidate: %d ",
816 compositor_needs_continuous_invalidate_
);
817 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
818 base::StringAppendF(&str
, "view width height: [%d %d] ", width_
, height_
);
819 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
820 base::StringAppendF(&str
, "hardware_initialized: %d ", hardware_initialized_
);
821 base::StringAppendF(&str
, "hardware_failed: %d ", hardware_failed_
);
822 base::StringAppendF(&str
,
823 "global visible rect: %s ",
824 cached_global_visible_rect_
.ToString().c_str());
825 base::StringAppendF(&str
,
826 "scroll_at_start_of_frame: %s ",
827 scroll_at_start_of_frame_
.ToString().c_str());
829 &str
, "scroll_offset_css: %s ", scroll_offset_css_
.ToString().c_str());
830 base::StringAppendF(&str
,
831 "overscroll_rounding_error_: %s ",
832 overscroll_rounding_error_
.ToString().c_str());
834 base::StringAppendF(&str
,
835 "clip left top right bottom: [%d %d %d %d] ",
836 draw_info
->clip_left
,
838 draw_info
->clip_right
,
839 draw_info
->clip_bottom
);
840 base::StringAppendF(&str
,
841 "surface width height: [%d %d] ",
844 base::StringAppendF(&str
, "is_layer: %d ", draw_info
->is_layer
);
849 } // namespace android_webview