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 "android_webview/browser/browser_view_renderer.h"
7 #include "android_webview/browser/browser_view_renderer_client.h"
8 #include "base/auto_reset.h"
9 #include "base/command_line.h"
10 #include "base/debug/trace_event_argument.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "cc/output/compositor_frame.h"
15 #include "content/public/common/content_switches.h"
16 #include "gpu/command_buffer/service/gpu_switches.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "third_party/skia/include/core/SkPicture.h"
20 #include "third_party/skia/include/core/SkPictureRecorder.h"
21 #include "ui/gfx/geometry/vector2d_conversions.h"
23 namespace android_webview
{
27 const int64 kFallbackTickTimeoutInMilliseconds
= 100;
29 // Used to calculate memory allocation. Determined experimentally.
30 const size_t kMemoryMultiplier
= 20;
31 const size_t kBytesPerPixel
= 4;
32 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
33 uint64 g_memory_override_in_bytes
= 0u;
38 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
39 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
41 // If the value was overridden on the command line, use the specified value.
42 bool client_hard_limit_bytes_overridden
=
43 cl
->HasSwitch(switches::kForceGpuMemAvailableMb
);
44 if (client_hard_limit_bytes_overridden
) {
46 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
47 switches::kForceGpuMemAvailableMb
),
48 &g_memory_override_in_bytes
);
49 g_memory_override_in_bytes
*= 1024 * 1024;
53 BrowserViewRenderer::BrowserViewRenderer(
54 BrowserViewRendererClient
* client
,
55 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
57 shared_renderer_state_(ui_task_runner
, this),
58 ui_task_runner_(ui_task_runner
),
62 window_visible_(false),
63 attached_to_window_(false),
64 hardware_enabled_(false),
66 page_scale_factor_(1.0),
67 on_new_picture_enable_(false),
69 compositor_needs_continuous_invalidate_(false),
70 invalidate_after_composite_(false),
71 block_invalidates_(false),
72 fallback_tick_pending_(false) {
75 BrowserViewRenderer::~BrowserViewRenderer() {
78 SharedRendererState
* BrowserViewRenderer::GetAwDrawGLViewContext() {
79 return &shared_renderer_state_
;
82 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion
) {
83 return client_
->RequestDrawGL(wait_for_completion
);
86 // This function updates the resource allocation in GlobalTileManager.
87 void BrowserViewRenderer::TrimMemory(const int level
, const bool visible
) {
88 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
89 // Constants from Android ComponentCallbacks2.
91 TRIM_MEMORY_RUNNING_LOW
= 10,
92 TRIM_MEMORY_UI_HIDDEN
= 20,
93 TRIM_MEMORY_BACKGROUND
= 40,
94 TRIM_MEMORY_MODERATE
= 60,
97 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
98 // it does not indicate memory pressure, but merely that the app is
100 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
103 // Do not release resources on view we expect to get DrawGL soon.
104 if (level
< TRIM_MEMORY_BACKGROUND
&& visible
)
108 if (!compositor_
|| !hardware_enabled_
)
111 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
113 // Drop everything in hardware.
114 if (level
>= TRIM_MEMORY_MODERATE
) {
115 shared_renderer_state_
.ReleaseHardwareDrawIfNeededOnUI();
119 // Just set the memory limit to 0 and drop all tiles. This will be reset to
120 // normal levels in the next DrawGL call.
121 compositor_
->SetMemoryPolicy(0u);
122 ForceFakeCompositeSW();
125 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
126 if (g_memory_override_in_bytes
)
127 return static_cast<size_t>(g_memory_override_in_bytes
);
129 size_t width
= last_on_draw_global_visible_rect_
.width();
130 size_t height
= last_on_draw_global_visible_rect_
.height();
131 size_t bytes_limit
= kMemoryMultiplier
* kBytesPerPixel
* width
* height
;
132 // Round up to a multiple of kMemoryAllocationStep.
134 (bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
138 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d
& scroll
,
139 const gfx::Rect
& global_visible_rect
) {
140 last_on_draw_scroll_offset_
= scroll
;
141 last_on_draw_global_visible_rect_
= global_visible_rect
;
144 bool BrowserViewRenderer::OnDrawHardware() {
145 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
146 shared_renderer_state_
.InitializeHardwareDrawIfNeededOnUI();
148 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
149 TRACE_EVENT_SCOPE_THREAD
);
153 shared_renderer_state_
.SetScrollOffsetOnUI(last_on_draw_scroll_offset_
);
155 if (!hardware_enabled_
) {
156 TRACE_EVENT0("android_webview", "InitializeHwDraw");
157 hardware_enabled_
= compositor_
->InitializeHwDraw();
159 if (!hardware_enabled_
) {
160 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_HardwareNotEnabled",
161 TRACE_EVENT_SCOPE_THREAD
);
165 if (last_on_draw_global_visible_rect_
.IsEmpty() &&
166 parent_draw_constraints_
.surface_rect
.IsEmpty()) {
167 TRACE_EVENT_INSTANT0("android_webview",
168 "EarlyOut_EmptyVisibleRect",
169 TRACE_EVENT_SCOPE_THREAD
);
170 shared_renderer_state_
.SetForceInvalidateOnNextDrawGLOnUI(true);
174 ReturnResourceFromParent();
175 if (shared_renderer_state_
.HasCompositorFrameOnUI()) {
176 TRACE_EVENT_INSTANT0("android_webview",
177 "EarlyOut_PreviousFrameUnconsumed",
178 TRACE_EVENT_SCOPE_THREAD
);
179 DidSkipCompositeInDraw();
183 scoped_ptr
<cc::CompositorFrame
> frame
= CompositeHw();
185 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
186 TRACE_EVENT_SCOPE_THREAD
);
190 shared_renderer_state_
.SetCompositorFrameOnUI(frame
.Pass(), false);
194 scoped_ptr
<cc::CompositorFrame
> BrowserViewRenderer::CompositeHw() {
195 compositor_
->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
197 parent_draw_constraints_
=
198 shared_renderer_state_
.GetParentDrawConstraintsOnUI();
199 gfx::Size
surface_size(size_
);
200 gfx::Rect
viewport(surface_size
);
201 gfx::Rect clip
= viewport
;
202 gfx::Transform transform_for_tile_priority
=
203 parent_draw_constraints_
.transform
;
205 // If the WebView is on a layer, WebView does not know what transform is
206 // applied onto the layer so global visible rect does not make sense here.
207 // In this case, just use the surface rect for tiling.
208 gfx::Rect viewport_rect_for_tile_priority
;
209 if (parent_draw_constraints_
.is_layer
||
210 last_on_draw_global_visible_rect_
.IsEmpty()) {
211 viewport_rect_for_tile_priority
= parent_draw_constraints_
.surface_rect
;
213 viewport_rect_for_tile_priority
= last_on_draw_global_visible_rect_
;
216 scoped_ptr
<cc::CompositorFrame
> frame
=
217 compositor_
->DemandDrawHw(surface_size
,
221 viewport_rect_for_tile_priority
,
222 transform_for_tile_priority
);
228 void BrowserViewRenderer::UpdateParentDrawConstraints() {
229 // Post an invalidate if the parent draw constraints are stale and there is
230 // no pending invalidate.
231 bool needs_force_invalidate
=
232 shared_renderer_state_
.NeedsForceInvalidateOnNextDrawGLOnUI();
233 if (needs_force_invalidate
||
234 !parent_draw_constraints_
.Equals(
235 shared_renderer_state_
.GetParentDrawConstraintsOnUI())) {
236 shared_renderer_state_
.SetForceInvalidateOnNextDrawGLOnUI(false);
237 EnsureContinuousInvalidation(true, needs_force_invalidate
);
241 void BrowserViewRenderer::ReturnUnusedResource(
242 scoped_ptr
<cc::CompositorFrame
> frame
) {
246 cc::CompositorFrameAck frame_ack
;
247 cc::TransferableResource::ReturnResources(
248 frame
->delegated_frame_data
->resource_list
, &frame_ack
.resources
);
249 if (compositor_
&& !frame_ack
.resources
.empty())
250 compositor_
->ReturnResources(frame_ack
);
253 void BrowserViewRenderer::ReturnResourceFromParent() {
254 cc::CompositorFrameAck frame_ack
;
255 shared_renderer_state_
.SwapReturnedResourcesOnUI(&frame_ack
.resources
);
256 if (compositor_
&& !frame_ack
.resources
.empty()) {
257 compositor_
->ReturnResources(frame_ack
);
261 void BrowserViewRenderer::DidSkipCommitFrame() {
262 // Treat it the same way as skipping onDraw.
263 DidSkipCompositeInDraw();
266 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
267 client_
->InvalidateOnFunctorDestroy();
270 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas
* canvas
) {
272 TRACE_EVENT_INSTANT0(
273 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
277 return CompositeSW(canvas
);
280 skia::RefPtr
<SkPicture
> BrowserViewRenderer::CapturePicture(int width
,
282 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
284 // Return empty Picture objects for empty SkPictures.
285 if (width
<= 0 || height
<= 0) {
286 SkPictureRecorder emptyRecorder
;
287 emptyRecorder
.beginRecording(0, 0);
288 return skia::AdoptRef(emptyRecorder
.endRecording());
291 // Reset scroll back to the origin, will go back to the old
292 // value when scroll_reset is out of scope.
293 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_dip_
,
296 SkPictureRecorder recorder
;
297 SkCanvas
* rec_canvas
= recorder
.beginRecording(width
, height
, NULL
, 0);
299 CompositeSW(rec_canvas
);
300 return skia::AdoptRef(recorder
.endRecording());
303 void BrowserViewRenderer::EnableOnNewPicture(bool enabled
) {
304 on_new_picture_enable_
= enabled
;
307 void BrowserViewRenderer::ClearView() {
308 TRACE_EVENT_INSTANT0("android_webview",
309 "BrowserViewRenderer::ClearView",
310 TRACE_EVENT_SCOPE_THREAD
);
315 // Always invalidate ignoring the compositor to actually clear the webview.
316 EnsureContinuousInvalidation(true, false);
319 void BrowserViewRenderer::SetIsPaused(bool paused
) {
320 TRACE_EVENT_INSTANT1("android_webview",
321 "BrowserViewRenderer::SetIsPaused",
322 TRACE_EVENT_SCOPE_THREAD
,
326 EnsureContinuousInvalidation(false, false);
329 void BrowserViewRenderer::SetViewVisibility(bool view_visible
) {
330 TRACE_EVENT_INSTANT1("android_webview",
331 "BrowserViewRenderer::SetViewVisibility",
332 TRACE_EVENT_SCOPE_THREAD
,
335 view_visible_
= view_visible
;
338 void BrowserViewRenderer::SetWindowVisibility(bool window_visible
) {
339 TRACE_EVENT_INSTANT1("android_webview",
340 "BrowserViewRenderer::SetWindowVisibility",
341 TRACE_EVENT_SCOPE_THREAD
,
344 window_visible_
= window_visible
;
345 EnsureContinuousInvalidation(false, false);
348 void BrowserViewRenderer::OnSizeChanged(int width
, int height
) {
349 TRACE_EVENT_INSTANT2("android_webview",
350 "BrowserViewRenderer::OnSizeChanged",
351 TRACE_EVENT_SCOPE_THREAD
,
356 size_
.SetSize(width
, height
);
359 void BrowserViewRenderer::OnAttachedToWindow(int width
, int height
) {
360 TRACE_EVENT2("android_webview",
361 "BrowserViewRenderer::OnAttachedToWindow",
366 attached_to_window_
= true;
367 size_
.SetSize(width
, height
);
370 void BrowserViewRenderer::OnDetachedFromWindow() {
371 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
372 shared_renderer_state_
.ReleaseHardwareDrawIfNeededOnUI();
373 attached_to_window_
= false;
374 DCHECK(!hardware_enabled_
);
377 void BrowserViewRenderer::ReleaseHardware() {
378 DCHECK(hardware_enabled_
);
379 ReturnUnusedResource(shared_renderer_state_
.PassUncommittedFrameOnUI());
380 ReturnResourceFromParent();
381 DCHECK(shared_renderer_state_
.ReturnedResourcesEmptyOnUI());
384 compositor_
->ReleaseHwDraw();
387 hardware_enabled_
= false;
390 bool BrowserViewRenderer::IsVisible() const {
391 // Ignore |window_visible_| if |attached_to_window_| is false.
392 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
395 gfx::Rect
BrowserViewRenderer::GetScreenRect() const {
396 return gfx::Rect(client_
->GetLocationOnScreen(), size_
);
399 void BrowserViewRenderer::DidInitializeCompositor(
400 content::SynchronousCompositor
* compositor
) {
401 TRACE_EVENT0("android_webview",
402 "BrowserViewRenderer::DidInitializeCompositor");
404 DCHECK(!compositor_
);
405 compositor_
= compositor
;
408 void BrowserViewRenderer::DidDestroyCompositor(
409 content::SynchronousCompositor
* compositor
) {
410 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
415 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate
) {
416 if (compositor_needs_continuous_invalidate_
== invalidate
)
419 TRACE_EVENT_INSTANT1("android_webview",
420 "BrowserViewRenderer::SetContinuousInvalidate",
421 TRACE_EVENT_SCOPE_THREAD
,
424 compositor_needs_continuous_invalidate_
= invalidate
;
426 EnsureContinuousInvalidation(false, false);
429 void BrowserViewRenderer::SetDipScale(float dip_scale
) {
430 dip_scale_
= dip_scale
;
431 CHECK_GT(dip_scale_
, 0);
434 gfx::Vector2d
BrowserViewRenderer::max_scroll_offset() const {
435 DCHECK_GT(dip_scale_
, 0);
436 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
437 max_scroll_offset_dip_
, dip_scale_
* page_scale_factor_
));
440 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset
) {
441 gfx::Vector2d max_offset
= max_scroll_offset();
442 gfx::Vector2dF scroll_offset_dip
;
443 // To preserve the invariant that scrolling to the maximum physical pixel
444 // value also scrolls to the maximum dip pixel value we transform the physical
445 // offset into the dip offset by using a proportion (instead of dividing by
446 // dip_scale * page_scale_factor).
447 if (max_offset
.x()) {
448 scroll_offset_dip
.set_x((scroll_offset
.x() * max_scroll_offset_dip_
.x()) /
451 if (max_offset
.y()) {
452 scroll_offset_dip
.set_y((scroll_offset
.y() * max_scroll_offset_dip_
.y()) /
456 DCHECK_LE(0, scroll_offset_dip
.x());
457 DCHECK_LE(0, scroll_offset_dip
.y());
458 DCHECK_LE(scroll_offset_dip
.x(), max_scroll_offset_dip_
.x());
459 DCHECK_LE(scroll_offset_dip
.y(), max_scroll_offset_dip_
.y());
461 if (scroll_offset_dip_
== scroll_offset_dip
)
464 scroll_offset_dip_
= scroll_offset_dip
;
466 TRACE_EVENT_INSTANT2("android_webview",
467 "BrowserViewRenderer::ScrollTo",
468 TRACE_EVENT_SCOPE_THREAD
,
470 scroll_offset_dip
.x(),
472 scroll_offset_dip
.y());
475 compositor_
->DidChangeRootLayerScrollOffset();
478 void BrowserViewRenderer::DidUpdateContent() {
479 TRACE_EVENT_INSTANT0("android_webview",
480 "BrowserViewRenderer::DidUpdateContent",
481 TRACE_EVENT_SCOPE_THREAD
);
483 if (on_new_picture_enable_
)
484 client_
->OnNewPicture();
487 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
488 gfx::Vector2dF scroll_offset_dip
) {
489 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
490 // DrawGl when http://crbug.com/249972 is fixed.
491 if (scroll_offset_dip_
== scroll_offset_dip
)
494 scroll_offset_dip_
= scroll_offset_dip
;
496 gfx::Vector2d max_offset
= max_scroll_offset();
497 gfx::Vector2d scroll_offset
;
498 // For an explanation as to why this is done this way see the comment in
499 // BrowserViewRenderer::ScrollTo.
500 if (max_scroll_offset_dip_
.x()) {
501 scroll_offset
.set_x((scroll_offset_dip
.x() * max_offset
.x()) /
502 max_scroll_offset_dip_
.x());
505 if (max_scroll_offset_dip_
.y()) {
506 scroll_offset
.set_y((scroll_offset_dip
.y() * max_offset
.y()) /
507 max_scroll_offset_dip_
.y());
510 DCHECK_LE(0, scroll_offset
.x());
511 DCHECK_LE(0, scroll_offset
.y());
512 DCHECK_LE(scroll_offset
.x(), max_offset
.x());
513 DCHECK_LE(scroll_offset
.y(), max_offset
.y());
515 client_
->ScrollContainerViewTo(scroll_offset
);
518 gfx::Vector2dF
BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
519 return scroll_offset_dip_
;
522 bool BrowserViewRenderer::IsExternalFlingActive() const {
523 return client_
->IsFlingActive();
526 void BrowserViewRenderer::UpdateRootLayerState(
527 const gfx::Vector2dF
& total_scroll_offset_dip
,
528 const gfx::Vector2dF
& max_scroll_offset_dip
,
529 const gfx::SizeF
& scrollable_size_dip
,
530 float page_scale_factor
,
531 float min_page_scale_factor
,
532 float max_page_scale_factor
) {
533 TRACE_EVENT_INSTANT1(
535 "BrowserViewRenderer::UpdateRootLayerState",
536 TRACE_EVENT_SCOPE_THREAD
,
538 RootLayerStateAsValue(total_scroll_offset_dip
, scrollable_size_dip
));
540 DCHECK_GT(dip_scale_
, 0);
542 max_scroll_offset_dip_
= max_scroll_offset_dip
;
543 DCHECK_LE(0, max_scroll_offset_dip_
.x());
544 DCHECK_LE(0, max_scroll_offset_dip_
.y());
546 page_scale_factor_
= page_scale_factor
;
547 DCHECK_GT(page_scale_factor_
, 0);
549 client_
->UpdateScrollState(max_scroll_offset(),
552 min_page_scale_factor
,
553 max_page_scale_factor
);
554 SetTotalRootLayerScrollOffset(total_scroll_offset_dip
);
557 scoped_refptr
<base::debug::ConvertableToTraceFormat
>
558 BrowserViewRenderer::RootLayerStateAsValue(
559 const gfx::Vector2dF
& total_scroll_offset_dip
,
560 const gfx::SizeF
& scrollable_size_dip
) {
561 scoped_refptr
<base::debug::TracedValue
> state
=
562 new base::debug::TracedValue();
564 state
->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip
.x());
565 state
->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip
.y());
567 state
->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_
.x());
568 state
->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_
.y());
570 state
->SetDouble("scrollable_size_dip.width", scrollable_size_dip
.width());
571 state
->SetDouble("scrollable_size_dip.height", scrollable_size_dip
.height());
573 state
->SetDouble("page_scale_factor", page_scale_factor_
);
577 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll
,
578 gfx::Vector2dF latest_overscroll_delta
,
579 gfx::Vector2dF current_fling_velocity
) {
580 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
581 if (accumulated_overscroll
== latest_overscroll_delta
)
582 overscroll_rounding_error_
= gfx::Vector2dF();
583 gfx::Vector2dF scaled_overscroll_delta
=
584 gfx::ScaleVector2d(latest_overscroll_delta
, physical_pixel_scale
);
585 gfx::Vector2d rounded_overscroll_delta
= gfx::ToRoundedVector2d(
586 scaled_overscroll_delta
+ overscroll_rounding_error_
);
587 overscroll_rounding_error_
=
588 scaled_overscroll_delta
- rounded_overscroll_delta
;
589 client_
->DidOverscroll(rounded_overscroll_delta
);
592 void BrowserViewRenderer::EnsureContinuousInvalidation(
593 bool force_invalidate
,
594 bool skip_reschedule_tick
) {
595 if (force_invalidate
)
596 invalidate_after_composite_
= true;
598 // This method should be called again when any of these conditions change.
599 bool need_invalidate
=
600 compositor_needs_continuous_invalidate_
|| invalidate_after_composite_
;
601 if (!need_invalidate
|| block_invalidates_
)
604 if (!compositor_needs_continuous_invalidate_
&& invalidate_after_composite_
)
605 invalidate_after_composite_
= false;
607 // Always call view invalidate. We rely the Android framework to ignore the
608 // invalidate when it's not needed such as when view is not visible.
609 client_
->PostInvalidate();
611 // Stop fallback ticks when one of these is true.
612 // 1) Webview is paused. Also need to check we are not in clear view since
613 // paused, offscreen still expect clear view to recover.
614 // 2) If we are attached to window and the window is not visible (eg when
615 // app is in the background). We are sure in this case the webview is used
616 // "on-screen" but that updates are not needed when in the background.
617 bool throttle_fallback_tick
=
618 (is_paused_
&& !clear_view_
) || (attached_to_window_
&& !window_visible_
);
619 if (throttle_fallback_tick
)
622 block_invalidates_
= compositor_needs_continuous_invalidate_
;
623 if (skip_reschedule_tick
&& fallback_tick_pending_
)
626 // Unretained here is safe because the callbacks are cancelled when
627 // they are destroyed.
628 post_fallback_tick_
.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick
,
629 base::Unretained(this)));
630 fallback_tick_fired_
.Cancel();
631 fallback_tick_pending_
= false;
633 // No need to reschedule fallback tick if compositor does not need to be
634 // ticked. This can happen if this is reached because force_invalidate is
636 if (compositor_needs_continuous_invalidate_
) {
637 fallback_tick_pending_
= true;
638 ui_task_runner_
->PostTask(FROM_HERE
, post_fallback_tick_
.callback());
642 void BrowserViewRenderer::PostFallbackTick() {
643 DCHECK(fallback_tick_fired_
.IsCancelled());
644 fallback_tick_fired_
.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired
,
645 base::Unretained(this)));
646 if (compositor_needs_continuous_invalidate_
) {
647 ui_task_runner_
->PostDelayedTask(
649 fallback_tick_fired_
.callback(),
650 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds
));
652 // Pretend we just composited to unblock further invalidates.
657 void BrowserViewRenderer::FallbackTickFired() {
658 TRACE_EVENT1("android_webview",
659 "BrowserViewRenderer::FallbackTickFired",
660 "compositor_needs_continuous_invalidate_",
661 compositor_needs_continuous_invalidate_
);
663 // This should only be called if OnDraw or DrawGL did not come in time, which
664 // means block_invalidates_ must still be true.
665 DCHECK(block_invalidates_
);
666 fallback_tick_pending_
= false;
667 if (compositor_needs_continuous_invalidate_
&& compositor_
) {
668 if (hardware_enabled_
) {
669 ReturnResourceFromParent();
670 ReturnUnusedResource(shared_renderer_state_
.PassUncommittedFrameOnUI());
671 scoped_ptr
<cc::CompositorFrame
> frame
= CompositeHw();
673 shared_renderer_state_
.SetCompositorFrameOnUI(frame
.Pass(), true);
676 ForceFakeCompositeSW();
679 // Pretend we just composited to unblock further invalidates.
684 void BrowserViewRenderer::ForceFakeCompositeSW() {
687 bitmap
.allocN32Pixels(1, 1);
688 bitmap
.eraseColor(0);
689 SkCanvas
canvas(bitmap
);
690 CompositeSW(&canvas
);
693 bool BrowserViewRenderer::CompositeSW(SkCanvas
* canvas
) {
695 ReturnResourceFromParent();
696 bool result
= compositor_
->DemandDrawSw(canvas
);
701 void BrowserViewRenderer::DidComposite() {
702 block_invalidates_
= false;
703 post_fallback_tick_
.Cancel();
704 fallback_tick_fired_
.Cancel();
705 fallback_tick_pending_
= false;
706 EnsureContinuousInvalidation(false, false);
709 void BrowserViewRenderer::DidSkipCompositeInDraw() {
710 block_invalidates_
= false;
711 EnsureContinuousInvalidation(true, true);
714 std::string
BrowserViewRenderer::ToString() const {
716 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
717 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
718 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
719 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
720 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
721 base::StringAppendF(&str
,
722 "compositor_needs_continuous_invalidate: %d ",
723 compositor_needs_continuous_invalidate_
);
724 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
725 base::StringAppendF(&str
, "view size: %s ", size_
.ToString().c_str());
726 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
727 base::StringAppendF(&str
,
728 "global visible rect: %s ",
729 last_on_draw_global_visible_rect_
.ToString().c_str());
731 &str
, "scroll_offset_dip: %s ", scroll_offset_dip_
.ToString().c_str());
732 base::StringAppendF(&str
,
733 "overscroll_rounding_error_: %s ",
734 overscroll_rounding_error_
.ToString().c_str());
736 &str
, "on_new_picture_enable: %d ", on_new_picture_enable_
);
737 base::StringAppendF(&str
, "clear_view: %d ", clear_view_
);
741 } // namespace android_webview