Download archives from the page_set's specified bucket in page_set_archive_info.
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blobd04181bd34887a9fb1fbdced7544ecf04d41acab
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 "android_webview/common/aw_switches.h"
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/debug/trace_event_argument.h"
12 #include "base/logging.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "cc/output/compositor_frame.h"
16 #include "content/public/common/content_switches.h"
17 #include "gpu/command_buffer/service/gpu_switches.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkPicture.h"
21 #include "third_party/skia/include/core/SkPictureRecorder.h"
22 #include "ui/gfx/geometry/vector2d_conversions.h"
24 namespace android_webview {
26 namespace {
28 const int64 kFallbackTickTimeoutInMilliseconds = 100;
30 // Used to calculate memory allocation. Determined experimentally.
31 const size_t kMemoryMultiplier = 20;
32 const size_t kBytesPerPixel = 4;
33 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
34 uint64 g_memory_override_in_bytes = 0u;
36 } // namespace
38 // static
39 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
40 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
42 // If the value was overridden on the command line, use the specified value.
43 bool client_hard_limit_bytes_overridden =
44 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
45 if (client_hard_limit_bytes_overridden) {
46 base::StringToUint64(
47 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
48 switches::kForceGpuMemAvailableMb),
49 &g_memory_override_in_bytes);
50 g_memory_override_in_bytes *= 1024 * 1024;
54 BrowserViewRenderer::BrowserViewRenderer(
55 BrowserViewRendererClient* client,
56 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
57 : client_(client),
58 shared_renderer_state_(ui_task_runner, this),
59 ui_task_runner_(ui_task_runner),
60 compositor_(NULL),
61 is_paused_(false),
62 view_visible_(false),
63 window_visible_(false),
64 attached_to_window_(false),
65 hardware_enabled_(false),
66 dip_scale_(0.0),
67 page_scale_factor_(1.0),
68 on_new_picture_enable_(false),
69 clear_view_(false),
70 compositor_needs_continuous_invalidate_(false),
71 invalidate_after_composite_(false),
72 block_invalidates_(false),
73 fallback_tick_pending_(false) {
76 BrowserViewRenderer::~BrowserViewRenderer() {
79 intptr_t BrowserViewRenderer::GetAwDrawGLViewContext() {
80 return reinterpret_cast<intptr_t>(&shared_renderer_state_);
83 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
84 return client_->RequestDrawGL(wait_for_completion);
87 // This function updates the resource allocation in GlobalTileManager.
88 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
89 DCHECK(ui_task_runner_->BelongsToCurrentThread());
90 // Constants from Android ComponentCallbacks2.
91 enum {
92 TRIM_MEMORY_RUNNING_LOW = 10,
93 TRIM_MEMORY_UI_HIDDEN = 20,
94 TRIM_MEMORY_BACKGROUND = 40,
95 TRIM_MEMORY_MODERATE = 60,
98 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
99 // it does not indicate memory pressure, but merely that the app is
100 // backgrounded.
101 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
102 return;
104 // Do not release resources on view we expect to get DrawGL soon.
105 if (level < TRIM_MEMORY_BACKGROUND && visible)
106 return;
108 // Nothing to drop.
109 if (!compositor_ || !hardware_enabled_)
110 return;
112 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
114 // Drop everything in hardware.
115 if (level >= TRIM_MEMORY_MODERATE) {
116 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
117 return;
120 // Just set the memory limit to 0 and drop all tiles. This will be reset to
121 // normal levels in the next DrawGL call.
122 compositor_->SetMemoryPolicy(0u);
123 ForceFakeCompositeSW();
126 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
127 if (g_memory_override_in_bytes)
128 return static_cast<size_t>(g_memory_override_in_bytes);
130 size_t width = last_on_draw_global_visible_rect_.width();
131 size_t height = last_on_draw_global_visible_rect_.height();
132 size_t bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
133 // Round up to a multiple of kMemoryAllocationStep.
134 bytes_limit =
135 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
136 return bytes_limit;
139 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d& scroll,
140 const gfx::Rect& global_visible_rect) {
141 last_on_draw_scroll_offset_ = scroll;
142 last_on_draw_global_visible_rect_ = global_visible_rect;
145 bool BrowserViewRenderer::OnDrawHardware() {
146 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
147 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
148 if (!compositor_)
149 return false;
151 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
153 if (!hardware_enabled_) {
154 hardware_enabled_ = compositor_->InitializeHwDraw();
156 if (!hardware_enabled_)
157 return false;
159 if (last_on_draw_global_visible_rect_.IsEmpty() &&
160 parent_draw_constraints_.surface_rect.IsEmpty()) {
161 TRACE_EVENT_INSTANT0("android_webview",
162 "EarlyOut_EmptyVisibleRect",
163 TRACE_EVENT_SCOPE_THREAD);
164 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(true);
165 return true;
168 ReturnResourceFromParent();
169 if (shared_renderer_state_.HasCompositorFrameOnUI()) {
170 TRACE_EVENT_INSTANT0("android_webview",
171 "EarlyOut_PreviousFrameUnconsumed",
172 TRACE_EVENT_SCOPE_THREAD);
173 DidSkipCompositeInDraw();
174 return true;
177 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
178 if (!frame.get())
179 return false;
181 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
182 return true;
185 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() {
186 compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
188 parent_draw_constraints_ =
189 shared_renderer_state_.GetParentDrawConstraintsOnUI();
190 gfx::Size surface_size(size_);
191 gfx::Rect viewport(surface_size);
192 gfx::Rect clip = viewport;
193 gfx::Transform transform_for_tile_priority =
194 parent_draw_constraints_.transform;
196 // If the WebView is on a layer, WebView does not know what transform is
197 // applied onto the layer so global visible rect does not make sense here.
198 // In this case, just use the surface rect for tiling.
199 gfx::Rect viewport_rect_for_tile_priority;
200 if (parent_draw_constraints_.is_layer ||
201 last_on_draw_global_visible_rect_.IsEmpty()) {
202 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
203 } else {
204 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
207 scoped_ptr<cc::CompositorFrame> frame =
208 compositor_->DemandDrawHw(surface_size,
209 gfx::Transform(),
210 viewport,
211 clip,
212 viewport_rect_for_tile_priority,
213 transform_for_tile_priority);
214 if (frame.get())
215 DidComposite();
216 return frame.Pass();
219 void BrowserViewRenderer::UpdateParentDrawConstraints() {
220 // Post an invalidate if the parent draw constraints are stale and there is
221 // no pending invalidate.
222 bool needs_force_invalidate =
223 shared_renderer_state_.NeedsForceInvalidateOnNextDrawGLOnUI();
224 if (needs_force_invalidate ||
225 !parent_draw_constraints_.Equals(
226 shared_renderer_state_.GetParentDrawConstraintsOnUI())) {
227 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(false);
228 EnsureContinuousInvalidation(true, needs_force_invalidate);
232 void BrowserViewRenderer::ReturnUnusedResource(
233 scoped_ptr<cc::CompositorFrame> frame) {
234 if (!frame.get())
235 return;
237 cc::CompositorFrameAck frame_ack;
238 cc::TransferableResource::ReturnResources(
239 frame->delegated_frame_data->resource_list, &frame_ack.resources);
240 if (compositor_ && !frame_ack.resources.empty())
241 compositor_->ReturnResources(frame_ack);
244 void BrowserViewRenderer::ReturnResourceFromParent() {
245 cc::CompositorFrameAck frame_ack;
246 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
247 if (compositor_ && !frame_ack.resources.empty()) {
248 compositor_->ReturnResources(frame_ack);
252 void BrowserViewRenderer::DidSkipCommitFrame() {
253 // Treat it the same way as skipping onDraw.
254 DidSkipCompositeInDraw();
257 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
258 client_->InvalidateOnFunctorDestroy();
261 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
262 if (!compositor_) {
263 TRACE_EVENT_INSTANT0(
264 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
265 return false;
268 return CompositeSW(canvas);
271 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
272 int height) {
273 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
275 // Return empty Picture objects for empty SkPictures.
276 if (width <= 0 || height <= 0) {
277 SkPictureRecorder emptyRecorder;
278 emptyRecorder.beginRecording(0, 0);
279 return skia::AdoptRef(emptyRecorder.endRecording());
282 // Reset scroll back to the origin, will go back to the old
283 // value when scroll_reset is out of scope.
284 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
285 gfx::Vector2dF());
287 SkPictureRecorder recorder;
288 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
289 if (compositor_)
290 CompositeSW(rec_canvas);
291 return skia::AdoptRef(recorder.endRecording());
294 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
295 on_new_picture_enable_ = enabled;
298 void BrowserViewRenderer::ClearView() {
299 TRACE_EVENT_INSTANT0("android_webview",
300 "BrowserViewRenderer::ClearView",
301 TRACE_EVENT_SCOPE_THREAD);
302 if (clear_view_)
303 return;
305 clear_view_ = true;
306 // Always invalidate ignoring the compositor to actually clear the webview.
307 EnsureContinuousInvalidation(true, false);
310 void BrowserViewRenderer::SetIsPaused(bool paused) {
311 TRACE_EVENT_INSTANT1("android_webview",
312 "BrowserViewRenderer::SetIsPaused",
313 TRACE_EVENT_SCOPE_THREAD,
314 "paused",
315 paused);
316 is_paused_ = paused;
317 EnsureContinuousInvalidation(false, false);
320 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
321 TRACE_EVENT_INSTANT1("android_webview",
322 "BrowserViewRenderer::SetViewVisibility",
323 TRACE_EVENT_SCOPE_THREAD,
324 "view_visible",
325 view_visible);
326 view_visible_ = view_visible;
329 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
330 TRACE_EVENT_INSTANT1("android_webview",
331 "BrowserViewRenderer::SetWindowVisibility",
332 TRACE_EVENT_SCOPE_THREAD,
333 "window_visible",
334 window_visible);
335 window_visible_ = window_visible;
336 EnsureContinuousInvalidation(false, false);
339 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
340 TRACE_EVENT_INSTANT2("android_webview",
341 "BrowserViewRenderer::OnSizeChanged",
342 TRACE_EVENT_SCOPE_THREAD,
343 "width",
344 width,
345 "height",
346 height);
347 size_.SetSize(width, height);
350 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
351 TRACE_EVENT2("android_webview",
352 "BrowserViewRenderer::OnAttachedToWindow",
353 "width",
354 width,
355 "height",
356 height);
357 attached_to_window_ = true;
358 size_.SetSize(width, height);
361 void BrowserViewRenderer::OnDetachedFromWindow() {
362 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
363 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
364 attached_to_window_ = false;
365 DCHECK(!hardware_enabled_);
368 void BrowserViewRenderer::ReleaseHardware() {
369 DCHECK(hardware_enabled_);
370 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
371 ReturnResourceFromParent();
372 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
374 if (compositor_) {
375 compositor_->ReleaseHwDraw();
378 hardware_enabled_ = false;
381 bool BrowserViewRenderer::IsVisible() const {
382 // Ignore |window_visible_| if |attached_to_window_| is false.
383 return view_visible_ && (!attached_to_window_ || window_visible_);
386 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
387 return gfx::Rect(client_->GetLocationOnScreen(), size_);
390 void BrowserViewRenderer::DidInitializeCompositor(
391 content::SynchronousCompositor* compositor) {
392 TRACE_EVENT0("android_webview",
393 "BrowserViewRenderer::DidInitializeCompositor");
394 DCHECK(compositor);
395 DCHECK(!compositor_);
396 compositor_ = compositor;
399 void BrowserViewRenderer::DidDestroyCompositor(
400 content::SynchronousCompositor* compositor) {
401 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
402 DCHECK(compositor_);
403 compositor_ = NULL;
406 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
407 if (compositor_needs_continuous_invalidate_ == invalidate)
408 return;
410 TRACE_EVENT_INSTANT1("android_webview",
411 "BrowserViewRenderer::SetContinuousInvalidate",
412 TRACE_EVENT_SCOPE_THREAD,
413 "invalidate",
414 invalidate);
415 compositor_needs_continuous_invalidate_ = invalidate;
417 EnsureContinuousInvalidation(false, false);
420 void BrowserViewRenderer::SetDipScale(float dip_scale) {
421 dip_scale_ = dip_scale;
422 CHECK_GT(dip_scale_, 0);
425 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
426 DCHECK_GT(dip_scale_, 0);
427 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
428 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
431 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
432 gfx::Vector2d max_offset = max_scroll_offset();
433 gfx::Vector2dF scroll_offset_dip;
434 // To preserve the invariant that scrolling to the maximum physical pixel
435 // value also scrolls to the maximum dip pixel value we transform the physical
436 // offset into the dip offset by using a proportion (instead of dividing by
437 // dip_scale * page_scale_factor).
438 if (max_offset.x()) {
439 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
440 max_offset.x());
442 if (max_offset.y()) {
443 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
444 max_offset.y());
447 DCHECK_LE(0, scroll_offset_dip.x());
448 DCHECK_LE(0, scroll_offset_dip.y());
449 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
450 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
452 if (scroll_offset_dip_ == scroll_offset_dip)
453 return;
455 scroll_offset_dip_ = scroll_offset_dip;
457 TRACE_EVENT_INSTANT2("android_webview",
458 "BrowserViewRenderer::ScrollTo",
459 TRACE_EVENT_SCOPE_THREAD,
460 "x",
461 scroll_offset_dip.x(),
462 "y",
463 scroll_offset_dip.y());
465 if (compositor_)
466 compositor_->DidChangeRootLayerScrollOffset();
469 void BrowserViewRenderer::DidUpdateContent() {
470 TRACE_EVENT_INSTANT0("android_webview",
471 "BrowserViewRenderer::DidUpdateContent",
472 TRACE_EVENT_SCOPE_THREAD);
473 clear_view_ = false;
474 if (on_new_picture_enable_)
475 client_->OnNewPicture();
478 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
479 gfx::Vector2dF scroll_offset_dip) {
480 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
481 // DrawGl when http://crbug.com/249972 is fixed.
482 if (scroll_offset_dip_ == scroll_offset_dip)
483 return;
485 scroll_offset_dip_ = scroll_offset_dip;
487 gfx::Vector2d max_offset = max_scroll_offset();
488 gfx::Vector2d scroll_offset;
489 // For an explanation as to why this is done this way see the comment in
490 // BrowserViewRenderer::ScrollTo.
491 if (max_scroll_offset_dip_.x()) {
492 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
493 max_scroll_offset_dip_.x());
496 if (max_scroll_offset_dip_.y()) {
497 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
498 max_scroll_offset_dip_.y());
501 DCHECK_LE(0, scroll_offset.x());
502 DCHECK_LE(0, scroll_offset.y());
503 DCHECK_LE(scroll_offset.x(), max_offset.x());
504 DCHECK_LE(scroll_offset.y(), max_offset.y());
506 client_->ScrollContainerViewTo(scroll_offset);
509 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
510 return scroll_offset_dip_;
513 bool BrowserViewRenderer::IsExternalFlingActive() const {
514 return client_->IsFlingActive();
517 void BrowserViewRenderer::UpdateRootLayerState(
518 const gfx::Vector2dF& total_scroll_offset_dip,
519 const gfx::Vector2dF& max_scroll_offset_dip,
520 const gfx::SizeF& scrollable_size_dip,
521 float page_scale_factor,
522 float min_page_scale_factor,
523 float max_page_scale_factor) {
524 TRACE_EVENT_INSTANT1(
525 "android_webview",
526 "BrowserViewRenderer::UpdateRootLayerState",
527 TRACE_EVENT_SCOPE_THREAD,
528 "state",
529 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
531 DCHECK_GT(dip_scale_, 0);
533 max_scroll_offset_dip_ = max_scroll_offset_dip;
534 DCHECK_LE(0, max_scroll_offset_dip_.x());
535 DCHECK_LE(0, max_scroll_offset_dip_.y());
537 page_scale_factor_ = page_scale_factor;
538 DCHECK_GT(page_scale_factor_, 0);
540 client_->UpdateScrollState(max_scroll_offset(),
541 scrollable_size_dip,
542 page_scale_factor,
543 min_page_scale_factor,
544 max_page_scale_factor);
545 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
548 scoped_refptr<base::debug::ConvertableToTraceFormat>
549 BrowserViewRenderer::RootLayerStateAsValue(
550 const gfx::Vector2dF& total_scroll_offset_dip,
551 const gfx::SizeF& scrollable_size_dip) {
552 scoped_refptr<base::debug::TracedValue> state =
553 new base::debug::TracedValue();
555 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
556 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
558 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
559 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
561 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
562 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
564 state->SetDouble("page_scale_factor", page_scale_factor_);
565 return state;
568 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
569 gfx::Vector2dF latest_overscroll_delta,
570 gfx::Vector2dF current_fling_velocity) {
571 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
572 if (accumulated_overscroll == latest_overscroll_delta)
573 overscroll_rounding_error_ = gfx::Vector2dF();
574 gfx::Vector2dF scaled_overscroll_delta =
575 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
576 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
577 scaled_overscroll_delta + overscroll_rounding_error_);
578 overscroll_rounding_error_ =
579 scaled_overscroll_delta - rounded_overscroll_delta;
580 client_->DidOverscroll(rounded_overscroll_delta);
583 void BrowserViewRenderer::EnsureContinuousInvalidation(
584 bool force_invalidate,
585 bool skip_reschedule_tick) {
586 if (force_invalidate)
587 invalidate_after_composite_ = true;
589 // This method should be called again when any of these conditions change.
590 bool need_invalidate =
591 compositor_needs_continuous_invalidate_ || invalidate_after_composite_;
592 if (!need_invalidate || block_invalidates_)
593 return;
595 if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_)
596 invalidate_after_composite_ = false;
598 // Always call view invalidate. We rely the Android framework to ignore the
599 // invalidate when it's not needed such as when view is not visible.
600 client_->PostInvalidate();
602 // Stop fallback ticks when one of these is true.
603 // 1) Webview is paused. Also need to check we are not in clear view since
604 // paused, offscreen still expect clear view to recover.
605 // 2) If we are attached to window and the window is not visible (eg when
606 // app is in the background). We are sure in this case the webview is used
607 // "on-screen" but that updates are not needed when in the background.
608 bool throttle_fallback_tick =
609 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
610 if (throttle_fallback_tick)
611 return;
613 block_invalidates_ = compositor_needs_continuous_invalidate_;
614 if (skip_reschedule_tick && fallback_tick_pending_)
615 return;
617 // Unretained here is safe because the callbacks are cancelled when
618 // they are destroyed.
619 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
620 base::Unretained(this)));
621 fallback_tick_fired_.Cancel();
622 fallback_tick_pending_ = false;
624 // No need to reschedule fallback tick if compositor does not need to be
625 // ticked. This can happen if this is reached because force_invalidate is
626 // true.
627 if (compositor_needs_continuous_invalidate_) {
628 fallback_tick_pending_ = true;
629 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
633 void BrowserViewRenderer::PostFallbackTick() {
634 DCHECK(fallback_tick_fired_.IsCancelled());
635 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
636 base::Unretained(this)));
637 if (compositor_needs_continuous_invalidate_) {
638 ui_task_runner_->PostDelayedTask(
639 FROM_HERE,
640 fallback_tick_fired_.callback(),
641 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
642 } else {
643 // Pretend we just composited to unblock further invalidates.
644 DidComposite();
648 void BrowserViewRenderer::FallbackTickFired() {
649 TRACE_EVENT1("android_webview",
650 "BrowserViewRenderer::FallbackTickFired",
651 "compositor_needs_continuous_invalidate_",
652 compositor_needs_continuous_invalidate_);
654 // This should only be called if OnDraw or DrawGL did not come in time, which
655 // means block_invalidates_ must still be true.
656 DCHECK(block_invalidates_);
657 fallback_tick_pending_ = false;
658 if (compositor_needs_continuous_invalidate_ && compositor_) {
659 if (hardware_enabled_) {
660 ReturnResourceFromParent();
661 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
662 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
663 if (frame.get()) {
664 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), true);
666 } else {
667 ForceFakeCompositeSW();
669 } else {
670 // Pretend we just composited to unblock further invalidates.
671 DidComposite();
675 void BrowserViewRenderer::ForceFakeCompositeSW() {
676 DCHECK(compositor_);
677 SkBitmap bitmap;
678 bitmap.allocN32Pixels(1, 1);
679 bitmap.eraseColor(0);
680 SkCanvas canvas(bitmap);
681 CompositeSW(&canvas);
684 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
685 DCHECK(compositor_);
686 ReturnResourceFromParent();
687 bool result = compositor_->DemandDrawSw(canvas);
688 DidComposite();
689 return result;
692 void BrowserViewRenderer::DidComposite() {
693 block_invalidates_ = false;
694 post_fallback_tick_.Cancel();
695 fallback_tick_fired_.Cancel();
696 fallback_tick_pending_ = false;
697 EnsureContinuousInvalidation(false, false);
700 void BrowserViewRenderer::DidSkipCompositeInDraw() {
701 block_invalidates_ = false;
702 EnsureContinuousInvalidation(true, true);
705 std::string BrowserViewRenderer::ToString() const {
706 std::string str;
707 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
708 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
709 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
710 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
711 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
712 base::StringAppendF(&str,
713 "compositor_needs_continuous_invalidate: %d ",
714 compositor_needs_continuous_invalidate_);
715 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
716 base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
717 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
718 base::StringAppendF(&str,
719 "global visible rect: %s ",
720 last_on_draw_global_visible_rect_.ToString().c_str());
721 base::StringAppendF(
722 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
723 base::StringAppendF(&str,
724 "overscroll_rounding_error_: %s ",
725 overscroll_rounding_error_.ToString().c_str());
726 base::StringAppendF(
727 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
728 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
729 return str;
732 } // namespace android_webview