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 double kEpsilon
= 1e-8;
29 const int64 kFallbackTickTimeoutInMilliseconds
= 100;
31 // Used to calculate memory allocation. Determined experimentally.
32 const size_t kMemoryMultiplier
= 20;
33 const size_t kBytesPerPixel
= 4;
34 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
35 uint64 g_memory_override_in_bytes
= 0u;
40 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
41 base::CommandLine
* cl
= base::CommandLine::ForCurrentProcess();
43 // If the value was overridden on the command line, use the specified value.
44 bool client_hard_limit_bytes_overridden
=
45 cl
->HasSwitch(switches::kForceGpuMemAvailableMb
);
46 if (client_hard_limit_bytes_overridden
) {
48 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
49 switches::kForceGpuMemAvailableMb
),
50 &g_memory_override_in_bytes
);
51 g_memory_override_in_bytes
*= 1024 * 1024;
55 BrowserViewRenderer::BrowserViewRenderer(
56 BrowserViewRendererClient
* client
,
57 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
59 shared_renderer_state_(ui_task_runner
, this),
60 ui_task_runner_(ui_task_runner
),
64 window_visible_(false),
65 attached_to_window_(false),
66 hardware_enabled_(false),
68 page_scale_factor_(1.0),
69 on_new_picture_enable_(false),
71 compositor_needs_continuous_invalidate_(false),
72 invalidate_after_composite_(false),
73 block_invalidates_(false),
74 fallback_tick_pending_(false) {
77 BrowserViewRenderer::~BrowserViewRenderer() {
80 SharedRendererState
* BrowserViewRenderer::GetAwDrawGLViewContext() {
81 return &shared_renderer_state_
;
84 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion
) {
85 return client_
->RequestDrawGL(wait_for_completion
);
88 // This function updates the resource allocation in GlobalTileManager.
89 void BrowserViewRenderer::TrimMemory(const int level
, const bool visible
) {
90 DCHECK(ui_task_runner_
->BelongsToCurrentThread());
91 // Constants from Android ComponentCallbacks2.
93 TRIM_MEMORY_RUNNING_LOW
= 10,
94 TRIM_MEMORY_UI_HIDDEN
= 20,
95 TRIM_MEMORY_BACKGROUND
= 40,
96 TRIM_MEMORY_MODERATE
= 60,
99 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
100 // it does not indicate memory pressure, but merely that the app is
102 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
105 // Do not release resources on view we expect to get DrawGL soon.
106 if (level
< TRIM_MEMORY_BACKGROUND
&& visible
)
110 if (!compositor_
|| !hardware_enabled_
)
113 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
115 // Drop everything in hardware.
116 if (level
>= TRIM_MEMORY_MODERATE
) {
117 shared_renderer_state_
.ReleaseHardwareDrawIfNeededOnUI();
121 // Just set the memory limit to 0 and drop all tiles. This will be reset to
122 // normal levels in the next DrawGL call.
123 compositor_
->SetMemoryPolicy(0u);
124 ForceFakeCompositeSW();
127 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
128 if (g_memory_override_in_bytes
)
129 return static_cast<size_t>(g_memory_override_in_bytes
);
131 size_t width
= last_on_draw_global_visible_rect_
.width();
132 size_t height
= last_on_draw_global_visible_rect_
.height();
133 size_t bytes_limit
= kMemoryMultiplier
* kBytesPerPixel
* width
* height
;
134 // Round up to a multiple of kMemoryAllocationStep.
136 (bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
140 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d
& scroll
,
141 const gfx::Rect
& global_visible_rect
) {
142 last_on_draw_scroll_offset_
= scroll
;
143 last_on_draw_global_visible_rect_
= global_visible_rect
;
146 bool BrowserViewRenderer::CanOnDraw() {
148 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
149 TRACE_EVENT_SCOPE_THREAD
);
153 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_ClearView",
154 TRACE_EVENT_SCOPE_THREAD
);
161 bool BrowserViewRenderer::OnDrawHardware() {
162 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
163 shared_renderer_state_
.InitializeHardwareDrawIfNeededOnUI();
169 shared_renderer_state_
.SetScrollOffsetOnUI(last_on_draw_scroll_offset_
);
171 if (!hardware_enabled_
) {
172 TRACE_EVENT0("android_webview", "InitializeHwDraw");
173 hardware_enabled_
= compositor_
->InitializeHwDraw();
175 if (!hardware_enabled_
) {
176 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_HardwareNotEnabled",
177 TRACE_EVENT_SCOPE_THREAD
);
181 if (last_on_draw_global_visible_rect_
.IsEmpty() &&
182 parent_draw_constraints_
.surface_rect
.IsEmpty()) {
183 TRACE_EVENT_INSTANT0("android_webview",
184 "EarlyOut_EmptyVisibleRect",
185 TRACE_EVENT_SCOPE_THREAD
);
186 shared_renderer_state_
.SetForceInvalidateOnNextDrawGLOnUI(true);
190 ReturnResourceFromParent();
191 if (shared_renderer_state_
.HasCompositorFrameOnUI()) {
192 TRACE_EVENT_INSTANT0("android_webview",
193 "EarlyOut_PreviousFrameUnconsumed",
194 TRACE_EVENT_SCOPE_THREAD
);
195 DidSkipCompositeInDraw();
199 scoped_ptr
<cc::CompositorFrame
> frame
= CompositeHw();
201 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
202 TRACE_EVENT_SCOPE_THREAD
);
206 shared_renderer_state_
.SetCompositorFrameOnUI(frame
.Pass(), false);
210 scoped_ptr
<cc::CompositorFrame
> BrowserViewRenderer::CompositeHw() {
211 compositor_
->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
213 parent_draw_constraints_
=
214 shared_renderer_state_
.GetParentDrawConstraintsOnUI();
215 gfx::Size
surface_size(size_
);
216 gfx::Rect
viewport(surface_size
);
217 gfx::Rect clip
= viewport
;
218 gfx::Transform transform_for_tile_priority
=
219 parent_draw_constraints_
.transform
;
221 // If the WebView is on a layer, WebView does not know what transform is
222 // applied onto the layer so global visible rect does not make sense here.
223 // In this case, just use the surface rect for tiling.
224 gfx::Rect viewport_rect_for_tile_priority
;
225 if (parent_draw_constraints_
.is_layer
||
226 last_on_draw_global_visible_rect_
.IsEmpty()) {
227 viewport_rect_for_tile_priority
= parent_draw_constraints_
.surface_rect
;
229 viewport_rect_for_tile_priority
= last_on_draw_global_visible_rect_
;
232 scoped_ptr
<cc::CompositorFrame
> frame
=
233 compositor_
->DemandDrawHw(surface_size
,
237 viewport_rect_for_tile_priority
,
238 transform_for_tile_priority
);
244 void BrowserViewRenderer::UpdateParentDrawConstraints() {
245 // Post an invalidate if the parent draw constraints are stale and there is
246 // no pending invalidate.
247 bool needs_force_invalidate
=
248 shared_renderer_state_
.NeedsForceInvalidateOnNextDrawGLOnUI();
249 if (needs_force_invalidate
||
250 !parent_draw_constraints_
.Equals(
251 shared_renderer_state_
.GetParentDrawConstraintsOnUI())) {
252 shared_renderer_state_
.SetForceInvalidateOnNextDrawGLOnUI(false);
253 EnsureContinuousInvalidation(true, needs_force_invalidate
);
257 void BrowserViewRenderer::ReturnUnusedResource(
258 scoped_ptr
<cc::CompositorFrame
> frame
) {
262 cc::CompositorFrameAck frame_ack
;
263 cc::TransferableResource::ReturnResources(
264 frame
->delegated_frame_data
->resource_list
, &frame_ack
.resources
);
265 if (compositor_
&& !frame_ack
.resources
.empty())
266 compositor_
->ReturnResources(frame_ack
);
269 void BrowserViewRenderer::ReturnResourceFromParent() {
270 cc::CompositorFrameAck frame_ack
;
271 shared_renderer_state_
.SwapReturnedResourcesOnUI(&frame_ack
.resources
);
272 if (compositor_
&& !frame_ack
.resources
.empty()) {
273 compositor_
->ReturnResources(frame_ack
);
277 void BrowserViewRenderer::DidSkipCommitFrame() {
278 // Treat it the same way as skipping onDraw.
279 DidSkipCompositeInDraw();
282 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
283 client_
->InvalidateOnFunctorDestroy();
286 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas
* canvas
) {
287 return CanOnDraw() && CompositeSW(canvas
);
290 skia::RefPtr
<SkPicture
> BrowserViewRenderer::CapturePicture(int width
,
292 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
294 // Return empty Picture objects for empty SkPictures.
295 if (width
<= 0 || height
<= 0) {
296 SkPictureRecorder emptyRecorder
;
297 emptyRecorder
.beginRecording(0, 0);
298 return skia::AdoptRef(emptyRecorder
.endRecording());
301 // Reset scroll back to the origin, will go back to the old
302 // value when scroll_reset is out of scope.
303 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_dip_
,
306 SkPictureRecorder recorder
;
307 SkCanvas
* rec_canvas
= recorder
.beginRecording(width
, height
, NULL
, 0);
309 CompositeSW(rec_canvas
);
310 return skia::AdoptRef(recorder
.endRecording());
313 void BrowserViewRenderer::EnableOnNewPicture(bool enabled
) {
314 on_new_picture_enable_
= enabled
;
317 void BrowserViewRenderer::ClearView() {
318 TRACE_EVENT_INSTANT0("android_webview",
319 "BrowserViewRenderer::ClearView",
320 TRACE_EVENT_SCOPE_THREAD
);
325 // Always invalidate ignoring the compositor to actually clear the webview.
326 EnsureContinuousInvalidation(true, false);
329 void BrowserViewRenderer::SetIsPaused(bool paused
) {
330 TRACE_EVENT_INSTANT1("android_webview",
331 "BrowserViewRenderer::SetIsPaused",
332 TRACE_EVENT_SCOPE_THREAD
,
336 EnsureContinuousInvalidation(false, false);
339 void BrowserViewRenderer::SetViewVisibility(bool view_visible
) {
340 TRACE_EVENT_INSTANT1("android_webview",
341 "BrowserViewRenderer::SetViewVisibility",
342 TRACE_EVENT_SCOPE_THREAD
,
345 view_visible_
= view_visible
;
348 void BrowserViewRenderer::SetWindowVisibility(bool window_visible
) {
349 TRACE_EVENT_INSTANT1("android_webview",
350 "BrowserViewRenderer::SetWindowVisibility",
351 TRACE_EVENT_SCOPE_THREAD
,
354 window_visible_
= window_visible
;
355 EnsureContinuousInvalidation(false, false);
358 void BrowserViewRenderer::OnSizeChanged(int width
, int height
) {
359 TRACE_EVENT_INSTANT2("android_webview",
360 "BrowserViewRenderer::OnSizeChanged",
361 TRACE_EVENT_SCOPE_THREAD
,
366 size_
.SetSize(width
, height
);
369 void BrowserViewRenderer::OnAttachedToWindow(int width
, int height
) {
370 TRACE_EVENT2("android_webview",
371 "BrowserViewRenderer::OnAttachedToWindow",
376 attached_to_window_
= true;
377 size_
.SetSize(width
, height
);
380 void BrowserViewRenderer::OnDetachedFromWindow() {
381 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
382 shared_renderer_state_
.ReleaseHardwareDrawIfNeededOnUI();
383 attached_to_window_
= false;
384 DCHECK(!hardware_enabled_
);
387 void BrowserViewRenderer::ReleaseHardware() {
388 DCHECK(hardware_enabled_
);
389 ReturnUnusedResource(shared_renderer_state_
.PassUncommittedFrameOnUI());
390 ReturnResourceFromParent();
391 DCHECK(shared_renderer_state_
.ReturnedResourcesEmptyOnUI());
394 compositor_
->ReleaseHwDraw();
397 hardware_enabled_
= false;
400 bool BrowserViewRenderer::IsVisible() const {
401 // Ignore |window_visible_| if |attached_to_window_| is false.
402 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
405 gfx::Rect
BrowserViewRenderer::GetScreenRect() const {
406 return gfx::Rect(client_
->GetLocationOnScreen(), size_
);
409 void BrowserViewRenderer::DidInitializeCompositor(
410 content::SynchronousCompositor
* compositor
) {
411 TRACE_EVENT0("android_webview",
412 "BrowserViewRenderer::DidInitializeCompositor");
414 DCHECK(!compositor_
);
415 compositor_
= compositor
;
418 void BrowserViewRenderer::DidDestroyCompositor(
419 content::SynchronousCompositor
* compositor
) {
420 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
425 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate
) {
426 if (compositor_needs_continuous_invalidate_
== invalidate
)
429 TRACE_EVENT_INSTANT1("android_webview",
430 "BrowserViewRenderer::SetContinuousInvalidate",
431 TRACE_EVENT_SCOPE_THREAD
,
434 compositor_needs_continuous_invalidate_
= invalidate
;
436 EnsureContinuousInvalidation(false, false);
439 void BrowserViewRenderer::SetDipScale(float dip_scale
) {
440 dip_scale_
= dip_scale
;
441 CHECK_GT(dip_scale_
, 0.f
);
444 gfx::Vector2d
BrowserViewRenderer::max_scroll_offset() const {
445 DCHECK_GT(dip_scale_
, 0.f
);
446 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
447 max_scroll_offset_dip_
, dip_scale_
* page_scale_factor_
));
450 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset
) {
451 gfx::Vector2d max_offset
= max_scroll_offset();
452 gfx::Vector2dF scroll_offset_dip
;
453 // To preserve the invariant that scrolling to the maximum physical pixel
454 // value also scrolls to the maximum dip pixel value we transform the physical
455 // offset into the dip offset by using a proportion (instead of dividing by
456 // dip_scale * page_scale_factor).
457 if (max_offset
.x()) {
458 scroll_offset_dip
.set_x((scroll_offset
.x() * max_scroll_offset_dip_
.x()) /
461 if (max_offset
.y()) {
462 scroll_offset_dip
.set_y((scroll_offset
.y() * max_scroll_offset_dip_
.y()) /
466 DCHECK_LE(0.f
, scroll_offset_dip
.x());
467 DCHECK_LE(0.f
, scroll_offset_dip
.y());
468 DCHECK(scroll_offset_dip
.x() < max_scroll_offset_dip_
.x() ||
469 scroll_offset_dip
.x() - max_scroll_offset_dip_
.x() < kEpsilon
)
470 << scroll_offset_dip
.x() << " " << max_scroll_offset_dip_
.x();
471 DCHECK(scroll_offset_dip
.y() < max_scroll_offset_dip_
.y() ||
472 scroll_offset_dip
.y() - max_scroll_offset_dip_
.y() < kEpsilon
)
473 << scroll_offset_dip
.y() << " " << max_scroll_offset_dip_
.y();
475 if (scroll_offset_dip_
== scroll_offset_dip
)
478 scroll_offset_dip_
= scroll_offset_dip
;
480 TRACE_EVENT_INSTANT2("android_webview",
481 "BrowserViewRenderer::ScrollTo",
482 TRACE_EVENT_SCOPE_THREAD
,
484 scroll_offset_dip
.x(),
486 scroll_offset_dip
.y());
489 compositor_
->DidChangeRootLayerScrollOffset();
492 void BrowserViewRenderer::DidUpdateContent() {
493 TRACE_EVENT_INSTANT0("android_webview",
494 "BrowserViewRenderer::DidUpdateContent",
495 TRACE_EVENT_SCOPE_THREAD
);
497 if (on_new_picture_enable_
)
498 client_
->OnNewPicture();
501 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
502 gfx::Vector2dF scroll_offset_dip
) {
503 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
504 // DrawGl when http://crbug.com/249972 is fixed.
505 if (scroll_offset_dip_
== scroll_offset_dip
)
508 scroll_offset_dip_
= scroll_offset_dip
;
510 gfx::Vector2d max_offset
= max_scroll_offset();
511 gfx::Vector2d scroll_offset
;
512 // For an explanation as to why this is done this way see the comment in
513 // BrowserViewRenderer::ScrollTo.
514 if (max_scroll_offset_dip_
.x()) {
515 scroll_offset
.set_x((scroll_offset_dip
.x() * max_offset
.x()) /
516 max_scroll_offset_dip_
.x());
519 if (max_scroll_offset_dip_
.y()) {
520 scroll_offset
.set_y((scroll_offset_dip
.y() * max_offset
.y()) /
521 max_scroll_offset_dip_
.y());
524 DCHECK_LE(0, scroll_offset
.x());
525 DCHECK_LE(0, scroll_offset
.y());
526 DCHECK_LE(scroll_offset
.x(), max_offset
.x());
527 DCHECK_LE(scroll_offset
.y(), max_offset
.y());
529 client_
->ScrollContainerViewTo(scroll_offset
);
532 gfx::Vector2dF
BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
533 return scroll_offset_dip_
;
536 bool BrowserViewRenderer::IsExternalFlingActive() const {
537 return client_
->IsFlingActive();
540 void BrowserViewRenderer::UpdateRootLayerState(
541 const gfx::Vector2dF
& total_scroll_offset_dip
,
542 const gfx::Vector2dF
& max_scroll_offset_dip
,
543 const gfx::SizeF
& scrollable_size_dip
,
544 float page_scale_factor
,
545 float min_page_scale_factor
,
546 float max_page_scale_factor
) {
547 TRACE_EVENT_INSTANT1(
549 "BrowserViewRenderer::UpdateRootLayerState",
550 TRACE_EVENT_SCOPE_THREAD
,
552 RootLayerStateAsValue(total_scroll_offset_dip
, scrollable_size_dip
));
554 DCHECK_GT(dip_scale_
, 0.f
);
556 max_scroll_offset_dip_
= max_scroll_offset_dip
;
557 DCHECK_LE(0.f
, max_scroll_offset_dip_
.x());
558 DCHECK_LE(0.f
, max_scroll_offset_dip_
.y());
560 page_scale_factor_
= page_scale_factor
;
561 DCHECK_GT(page_scale_factor_
, 0.f
);
563 client_
->UpdateScrollState(max_scroll_offset(),
566 min_page_scale_factor
,
567 max_page_scale_factor
);
568 SetTotalRootLayerScrollOffset(total_scroll_offset_dip
);
571 scoped_refptr
<base::debug::ConvertableToTraceFormat
>
572 BrowserViewRenderer::RootLayerStateAsValue(
573 const gfx::Vector2dF
& total_scroll_offset_dip
,
574 const gfx::SizeF
& scrollable_size_dip
) {
575 scoped_refptr
<base::debug::TracedValue
> state
=
576 new base::debug::TracedValue();
578 state
->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip
.x());
579 state
->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip
.y());
581 state
->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_
.x());
582 state
->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_
.y());
584 state
->SetDouble("scrollable_size_dip.width", scrollable_size_dip
.width());
585 state
->SetDouble("scrollable_size_dip.height", scrollable_size_dip
.height());
587 state
->SetDouble("page_scale_factor", page_scale_factor_
);
591 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll
,
592 gfx::Vector2dF latest_overscroll_delta
,
593 gfx::Vector2dF current_fling_velocity
) {
594 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
595 if (accumulated_overscroll
== latest_overscroll_delta
)
596 overscroll_rounding_error_
= gfx::Vector2dF();
597 gfx::Vector2dF scaled_overscroll_delta
=
598 gfx::ScaleVector2d(latest_overscroll_delta
, physical_pixel_scale
);
599 gfx::Vector2d rounded_overscroll_delta
= gfx::ToRoundedVector2d(
600 scaled_overscroll_delta
+ overscroll_rounding_error_
);
601 overscroll_rounding_error_
=
602 scaled_overscroll_delta
- rounded_overscroll_delta
;
603 client_
->DidOverscroll(rounded_overscroll_delta
);
606 void BrowserViewRenderer::EnsureContinuousInvalidation(
607 bool force_invalidate
,
608 bool skip_reschedule_tick
) {
609 if (force_invalidate
)
610 invalidate_after_composite_
= true;
612 // This method should be called again when any of these conditions change.
613 bool need_invalidate
=
614 compositor_needs_continuous_invalidate_
|| invalidate_after_composite_
;
615 if (!need_invalidate
|| block_invalidates_
)
618 if (!compositor_needs_continuous_invalidate_
&& invalidate_after_composite_
)
619 invalidate_after_composite_
= false;
621 // Always call view invalidate. We rely the Android framework to ignore the
622 // invalidate when it's not needed such as when view is not visible.
623 client_
->PostInvalidate();
625 // Stop fallback ticks when one of these is true.
626 // 1) Webview is paused. Also need to check we are not in clear view since
627 // paused, offscreen still expect clear view to recover.
628 // 2) If we are attached to window and the window is not visible (eg when
629 // app is in the background). We are sure in this case the webview is used
630 // "on-screen" but that updates are not needed when in the background.
631 bool throttle_fallback_tick
=
632 (is_paused_
&& !clear_view_
) || (attached_to_window_
&& !window_visible_
);
633 if (throttle_fallback_tick
)
636 block_invalidates_
= compositor_needs_continuous_invalidate_
;
637 if (skip_reschedule_tick
&& fallback_tick_pending_
)
640 // Unretained here is safe because the callbacks are cancelled when
641 // they are destroyed.
642 post_fallback_tick_
.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick
,
643 base::Unretained(this)));
644 fallback_tick_fired_
.Cancel();
645 fallback_tick_pending_
= false;
647 // No need to reschedule fallback tick if compositor does not need to be
648 // ticked. This can happen if this is reached because force_invalidate is
650 if (compositor_needs_continuous_invalidate_
) {
651 fallback_tick_pending_
= true;
652 ui_task_runner_
->PostTask(FROM_HERE
, post_fallback_tick_
.callback());
656 void BrowserViewRenderer::PostFallbackTick() {
657 DCHECK(fallback_tick_fired_
.IsCancelled());
658 fallback_tick_fired_
.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired
,
659 base::Unretained(this)));
660 if (compositor_needs_continuous_invalidate_
) {
661 ui_task_runner_
->PostDelayedTask(
663 fallback_tick_fired_
.callback(),
664 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds
));
666 // Pretend we just composited to unblock further invalidates.
671 void BrowserViewRenderer::FallbackTickFired() {
672 TRACE_EVENT1("android_webview",
673 "BrowserViewRenderer::FallbackTickFired",
674 "compositor_needs_continuous_invalidate_",
675 compositor_needs_continuous_invalidate_
);
677 // This should only be called if OnDraw or DrawGL did not come in time, which
678 // means block_invalidates_ must still be true.
679 DCHECK(block_invalidates_
);
680 fallback_tick_pending_
= false;
681 if (compositor_needs_continuous_invalidate_
&& compositor_
) {
682 if (hardware_enabled_
) {
683 ReturnResourceFromParent();
684 ReturnUnusedResource(shared_renderer_state_
.PassUncommittedFrameOnUI());
685 scoped_ptr
<cc::CompositorFrame
> frame
= CompositeHw();
687 shared_renderer_state_
.SetCompositorFrameOnUI(frame
.Pass(), true);
690 ForceFakeCompositeSW();
693 // Pretend we just composited to unblock further invalidates.
698 void BrowserViewRenderer::ForceFakeCompositeSW() {
701 bitmap
.allocN32Pixels(1, 1);
702 bitmap
.eraseColor(0);
703 SkCanvas
canvas(bitmap
);
704 CompositeSW(&canvas
);
707 bool BrowserViewRenderer::CompositeSW(SkCanvas
* canvas
) {
709 ReturnResourceFromParent();
710 bool result
= compositor_
->DemandDrawSw(canvas
);
715 void BrowserViewRenderer::DidComposite() {
716 block_invalidates_
= false;
717 post_fallback_tick_
.Cancel();
718 fallback_tick_fired_
.Cancel();
719 fallback_tick_pending_
= false;
720 EnsureContinuousInvalidation(false, false);
723 void BrowserViewRenderer::DidSkipCompositeInDraw() {
724 block_invalidates_
= false;
725 EnsureContinuousInvalidation(true, true);
728 std::string
BrowserViewRenderer::ToString() const {
730 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
731 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
732 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
733 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
734 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
735 base::StringAppendF(&str
,
736 "compositor_needs_continuous_invalidate: %d ",
737 compositor_needs_continuous_invalidate_
);
738 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
739 base::StringAppendF(&str
, "view size: %s ", size_
.ToString().c_str());
740 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
741 base::StringAppendF(&str
,
742 "global visible rect: %s ",
743 last_on_draw_global_visible_rect_
.ToString().c_str());
745 &str
, "scroll_offset_dip: %s ", scroll_offset_dip_
.ToString().c_str());
746 base::StringAppendF(&str
,
747 "overscroll_rounding_error_: %s ",
748 overscroll_rounding_error_
.ToString().c_str());
750 &str
, "on_new_picture_enable: %d ", on_new_picture_enable_
);
751 base::StringAppendF(&str
, "clear_view: %d ", clear_view_
);
755 } // namespace android_webview