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/browser/shared_renderer_state.h"
9 #include "android_webview/common/aw_switches.h"
10 #include "base/auto_reset.h"
11 #include "base/command_line.h"
12 #include "base/debug/trace_event_argument.h"
13 #include "base/logging.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "cc/output/compositor_frame.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/content_switches.h"
19 #include "gpu/command_buffer/service/gpu_switches.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkPicture.h"
23 #include "third_party/skia/include/core/SkPictureRecorder.h"
24 #include "ui/gfx/geometry/vector2d_conversions.h"
26 namespace android_webview {
30 const int64 kFallbackTickTimeoutInMilliseconds = 100;
32 // Used to calculate memory allocation. Determined experimentally.
33 const size_t kMemoryMultiplier = 20;
34 const size_t kBytesPerPixel = 4;
35 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
36 uint64 g_memory_override_in_bytes = 0u;
41 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
42 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
44 // If the value was overridden on the command line, use the specified value.
45 bool client_hard_limit_bytes_overridden =
46 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
47 if (client_hard_limit_bytes_overridden) {
49 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
50 switches::kForceGpuMemAvailableMb),
51 &g_memory_override_in_bytes);
52 g_memory_override_in_bytes *= 1024 * 1024;
56 BrowserViewRenderer::BrowserViewRenderer(
57 BrowserViewRendererClient* client,
58 content::WebContents* web_contents,
59 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
61 shared_renderer_state_(ui_task_runner, this),
62 web_contents_(web_contents),
63 ui_task_runner_(ui_task_runner),
67 window_visible_(false),
68 attached_to_window_(false),
69 hardware_enabled_(false),
71 page_scale_factor_(1.0),
72 on_new_picture_enable_(false),
74 compositor_needs_continuous_invalidate_(false),
75 invalidate_after_composite_(false),
76 block_invalidates_(false),
77 fallback_tick_pending_(false),
81 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
83 // Currently the logic in this class relies on |compositor_| remaining
84 // NULL until the DidInitializeCompositor() call, hence it is not set here.
87 BrowserViewRenderer::~BrowserViewRenderer() {
88 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
89 // OnDetachedFromWindow should be called before the destructor, so the memory
90 // policy should have already been updated.
93 intptr_t BrowserViewRenderer::GetAwDrawGLViewContext() {
94 return reinterpret_cast<intptr_t>(&shared_renderer_state_);
97 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
98 return client_->RequestDrawGL(wait_for_completion);
101 // This function updates the resource allocation in GlobalTileManager.
102 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
103 DCHECK(ui_task_runner_->BelongsToCurrentThread());
104 // Constants from Android ComponentCallbacks2.
106 TRIM_MEMORY_RUNNING_LOW = 10,
107 TRIM_MEMORY_UI_HIDDEN = 20,
108 TRIM_MEMORY_BACKGROUND = 40,
109 TRIM_MEMORY_MODERATE = 60,
112 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
113 // it does not indicate memory pressure, but merely that the app is
115 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
118 // Do not release resources on view we expect to get DrawGL soon.
119 if (level < TRIM_MEMORY_BACKGROUND && visible)
123 if (!compositor_ || !hardware_enabled_)
126 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
128 // Drop everything in hardware.
129 if (level >= TRIM_MEMORY_MODERATE) {
130 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
134 // Just set the memory limit to 0 and drop all tiles. This will be reset to
135 // normal levels in the next DrawGL call.
136 compositor_->SetMemoryPolicy(0u);
137 ForceFakeCompositeSW();
140 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
141 if (g_memory_override_in_bytes)
142 return static_cast<size_t>(g_memory_override_in_bytes);
144 size_t width = last_on_draw_global_visible_rect_.width();
145 size_t height = last_on_draw_global_visible_rect_.height();
146 size_t bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
147 // Round up to a multiple of kMemoryAllocationStep.
149 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
153 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
154 bool is_hardware_canvas,
155 const gfx::Vector2d& scroll,
156 const gfx::Rect& global_visible_rect) {
157 last_on_draw_scroll_offset_ = scroll;
158 last_on_draw_global_visible_rect_ = global_visible_rect;
163 if (is_hardware_canvas && attached_to_window_ &&
164 !switches::ForceAuxiliaryBitmap()) {
165 return OnDrawHardware();
168 // Perform a software draw
169 return OnDrawSoftware(java_canvas);
172 bool BrowserViewRenderer::OnDrawHardware() {
173 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
174 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
178 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
180 if (!hardware_enabled_) {
181 hardware_enabled_ = compositor_->InitializeHwDraw();
183 if (!hardware_enabled_)
186 if (last_on_draw_global_visible_rect_.IsEmpty() &&
187 parent_draw_constraints_.surface_rect.IsEmpty()) {
188 TRACE_EVENT_INSTANT0("android_webview",
189 "EarlyOut_EmptyVisibleRect",
190 TRACE_EVENT_SCOPE_THREAD);
191 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(true);
195 ReturnResourceFromParent();
196 if (shared_renderer_state_.HasCompositorFrameOnUI()) {
197 TRACE_EVENT_INSTANT0("android_webview",
198 "EarlyOut_PreviousFrameUnconsumed",
199 TRACE_EVENT_SCOPE_THREAD);
200 DidSkipCompositeInDraw();
204 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
208 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
212 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() {
213 compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
215 parent_draw_constraints_ =
216 shared_renderer_state_.GetParentDrawConstraintsOnUI();
217 gfx::Size surface_size(width_, height_);
218 gfx::Rect viewport(surface_size);
219 gfx::Rect clip = viewport;
220 gfx::Transform transform_for_tile_priority =
221 parent_draw_constraints_.transform;
223 // If the WebView is on a layer, WebView does not know what transform is
224 // applied onto the layer so global visible rect does not make sense here.
225 // In this case, just use the surface rect for tiling.
226 gfx::Rect viewport_rect_for_tile_priority;
227 if (parent_draw_constraints_.is_layer ||
228 last_on_draw_global_visible_rect_.IsEmpty()) {
229 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
231 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
234 scoped_ptr<cc::CompositorFrame> frame =
235 compositor_->DemandDrawHw(surface_size,
239 viewport_rect_for_tile_priority,
240 transform_for_tile_priority);
246 void BrowserViewRenderer::UpdateParentDrawConstraints() {
247 // Post an invalidate if the parent draw constraints are stale and there is
248 // no pending invalidate.
249 bool needs_force_invalidate =
250 shared_renderer_state_.NeedsForceInvalidateOnNextDrawGLOnUI();
251 if (needs_force_invalidate ||
252 !parent_draw_constraints_.Equals(
253 shared_renderer_state_.GetParentDrawConstraintsOnUI())) {
254 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(false);
255 EnsureContinuousInvalidation(true, needs_force_invalidate);
259 void BrowserViewRenderer::ReturnUnusedResource(
260 scoped_ptr<cc::CompositorFrame> frame) {
264 cc::CompositorFrameAck frame_ack;
265 cc::TransferableResource::ReturnResources(
266 frame->delegated_frame_data->resource_list, &frame_ack.resources);
267 if (compositor_ && !frame_ack.resources.empty())
268 compositor_->ReturnResources(frame_ack);
271 void BrowserViewRenderer::ReturnResourceFromParent() {
272 cc::CompositorFrameAck frame_ack;
273 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
274 if (compositor_ && !frame_ack.resources.empty()) {
275 compositor_->ReturnResources(frame_ack);
279 void BrowserViewRenderer::DidSkipCommitFrame() {
280 // Treat it the same way as skipping onDraw.
281 DidSkipCompositeInDraw();
284 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
285 client_->InvalidateOnFunctorDestroy();
288 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) {
290 TRACE_EVENT_INSTANT0(
291 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
295 // TODO(hush): right now webview size is passed in as the auxiliary bitmap
296 // size, which might hurt performace (only for software draws with auxiliary
297 // bitmap). For better performance, get global visible rect, transform it
298 // from screen space to view space, then intersect with the webview in
299 // viewspace. Use the resulting rect as the auxiliary
301 return BrowserViewRendererJavaHelper::GetInstance()
302 ->RenderViaAuxilaryBitmapIfNeeded(
304 last_on_draw_scroll_offset_,
305 gfx::Size(width_, height_),
306 base::Bind(&BrowserViewRenderer::CompositeSW,
307 base::Unretained(this)));
310 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
312 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
314 // Return empty Picture objects for empty SkPictures.
315 if (width <= 0 || height <= 0) {
316 SkPictureRecorder emptyRecorder;
317 emptyRecorder.beginRecording(0, 0);
318 return skia::AdoptRef(emptyRecorder.endRecording());
321 // Reset scroll back to the origin, will go back to the old
322 // value when scroll_reset is out of scope.
323 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
326 SkPictureRecorder recorder;
327 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
329 CompositeSW(rec_canvas);
330 return skia::AdoptRef(recorder.endRecording());
333 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
334 on_new_picture_enable_ = enabled;
337 void BrowserViewRenderer::ClearView() {
338 TRACE_EVENT_INSTANT0("android_webview",
339 "BrowserViewRenderer::ClearView",
340 TRACE_EVENT_SCOPE_THREAD);
345 // Always invalidate ignoring the compositor to actually clear the webview.
346 EnsureContinuousInvalidation(true, false);
349 void BrowserViewRenderer::SetIsPaused(bool paused) {
350 TRACE_EVENT_INSTANT1("android_webview",
351 "BrowserViewRenderer::SetIsPaused",
352 TRACE_EVENT_SCOPE_THREAD,
356 EnsureContinuousInvalidation(false, false);
359 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
360 TRACE_EVENT_INSTANT1("android_webview",
361 "BrowserViewRenderer::SetViewVisibility",
362 TRACE_EVENT_SCOPE_THREAD,
365 view_visible_ = view_visible;
368 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
369 TRACE_EVENT_INSTANT1("android_webview",
370 "BrowserViewRenderer::SetWindowVisibility",
371 TRACE_EVENT_SCOPE_THREAD,
374 window_visible_ = window_visible;
375 EnsureContinuousInvalidation(false, false);
378 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
379 TRACE_EVENT_INSTANT2("android_webview",
380 "BrowserViewRenderer::OnSizeChanged",
381 TRACE_EVENT_SCOPE_THREAD,
390 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
391 TRACE_EVENT2("android_webview",
392 "BrowserViewRenderer::OnAttachedToWindow",
397 attached_to_window_ = true;
402 void BrowserViewRenderer::OnDetachedFromWindow() {
403 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
404 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
405 attached_to_window_ = false;
406 DCHECK(!hardware_enabled_);
409 void BrowserViewRenderer::ReleaseHardware() {
410 DCHECK(hardware_enabled_);
411 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
412 ReturnResourceFromParent();
413 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
416 compositor_->ReleaseHwDraw();
419 hardware_enabled_ = false;
422 bool BrowserViewRenderer::IsVisible() const {
423 // Ignore |window_visible_| if |attached_to_window_| is false.
424 return view_visible_ && (!attached_to_window_ || window_visible_);
427 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
428 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
431 void BrowserViewRenderer::DidInitializeCompositor(
432 content::SynchronousCompositor* compositor) {
433 TRACE_EVENT0("android_webview",
434 "BrowserViewRenderer::DidInitializeCompositor");
436 DCHECK(!compositor_);
437 compositor_ = compositor;
440 void BrowserViewRenderer::DidDestroyCompositor(
441 content::SynchronousCompositor* compositor) {
442 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
447 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
448 if (compositor_needs_continuous_invalidate_ == invalidate)
451 TRACE_EVENT_INSTANT1("android_webview",
452 "BrowserViewRenderer::SetContinuousInvalidate",
453 TRACE_EVENT_SCOPE_THREAD,
456 compositor_needs_continuous_invalidate_ = invalidate;
458 EnsureContinuousInvalidation(false, false);
461 void BrowserViewRenderer::SetDipScale(float dip_scale) {
462 dip_scale_ = dip_scale;
463 CHECK_GT(dip_scale_, 0);
466 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
467 DCHECK_GT(dip_scale_, 0);
468 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
469 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
472 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
473 gfx::Vector2d max_offset = max_scroll_offset();
474 gfx::Vector2dF scroll_offset_dip;
475 // To preserve the invariant that scrolling to the maximum physical pixel
476 // value also scrolls to the maximum dip pixel value we transform the physical
477 // offset into the dip offset by using a proportion (instead of dividing by
478 // dip_scale * page_scale_factor).
479 if (max_offset.x()) {
480 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
483 if (max_offset.y()) {
484 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
488 DCHECK_LE(0, scroll_offset_dip.x());
489 DCHECK_LE(0, scroll_offset_dip.y());
490 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
491 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
493 if (scroll_offset_dip_ == scroll_offset_dip)
496 scroll_offset_dip_ = scroll_offset_dip;
498 TRACE_EVENT_INSTANT2("android_webview",
499 "BrowserViewRenderer::ScrollTo",
500 TRACE_EVENT_SCOPE_THREAD,
502 scroll_offset_dip.x(),
504 scroll_offset_dip.y());
507 compositor_->DidChangeRootLayerScrollOffset();
510 void BrowserViewRenderer::DidUpdateContent() {
511 TRACE_EVENT_INSTANT0("android_webview",
512 "BrowserViewRenderer::DidUpdateContent",
513 TRACE_EVENT_SCOPE_THREAD);
515 if (on_new_picture_enable_)
516 client_->OnNewPicture();
519 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
520 gfx::Vector2dF scroll_offset_dip) {
521 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
522 // DrawGl when http://crbug.com/249972 is fixed.
523 if (scroll_offset_dip_ == scroll_offset_dip)
526 scroll_offset_dip_ = scroll_offset_dip;
528 gfx::Vector2d max_offset = max_scroll_offset();
529 gfx::Vector2d scroll_offset;
530 // For an explanation as to why this is done this way see the comment in
531 // BrowserViewRenderer::ScrollTo.
532 if (max_scroll_offset_dip_.x()) {
533 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
534 max_scroll_offset_dip_.x());
537 if (max_scroll_offset_dip_.y()) {
538 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
539 max_scroll_offset_dip_.y());
542 DCHECK_LE(0, scroll_offset.x());
543 DCHECK_LE(0, scroll_offset.y());
544 DCHECK_LE(scroll_offset.x(), max_offset.x());
545 DCHECK_LE(scroll_offset.y(), max_offset.y());
547 client_->ScrollContainerViewTo(scroll_offset);
550 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
551 return scroll_offset_dip_;
554 bool BrowserViewRenderer::IsExternalFlingActive() const {
555 return client_->IsFlingActive();
558 void BrowserViewRenderer::UpdateRootLayerState(
559 const gfx::Vector2dF& total_scroll_offset_dip,
560 const gfx::Vector2dF& max_scroll_offset_dip,
561 const gfx::SizeF& scrollable_size_dip,
562 float page_scale_factor,
563 float min_page_scale_factor,
564 float max_page_scale_factor) {
565 TRACE_EVENT_INSTANT1(
567 "BrowserViewRenderer::UpdateRootLayerState",
568 TRACE_EVENT_SCOPE_THREAD,
570 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
572 DCHECK_GT(dip_scale_, 0);
574 max_scroll_offset_dip_ = max_scroll_offset_dip;
575 DCHECK_LE(0, max_scroll_offset_dip_.x());
576 DCHECK_LE(0, max_scroll_offset_dip_.y());
578 page_scale_factor_ = page_scale_factor;
579 DCHECK_GT(page_scale_factor_, 0);
581 client_->UpdateScrollState(max_scroll_offset(),
584 min_page_scale_factor,
585 max_page_scale_factor);
586 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
589 scoped_refptr<base::debug::ConvertableToTraceFormat>
590 BrowserViewRenderer::RootLayerStateAsValue(
591 const gfx::Vector2dF& total_scroll_offset_dip,
592 const gfx::SizeF& scrollable_size_dip) {
593 scoped_refptr<base::debug::TracedValue> state =
594 new base::debug::TracedValue();
596 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
597 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
599 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
600 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
602 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
603 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
605 state->SetDouble("page_scale_factor", page_scale_factor_);
609 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
610 gfx::Vector2dF latest_overscroll_delta,
611 gfx::Vector2dF current_fling_velocity) {
612 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
613 if (accumulated_overscroll == latest_overscroll_delta)
614 overscroll_rounding_error_ = gfx::Vector2dF();
615 gfx::Vector2dF scaled_overscroll_delta =
616 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
617 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
618 scaled_overscroll_delta + overscroll_rounding_error_);
619 overscroll_rounding_error_ =
620 scaled_overscroll_delta - rounded_overscroll_delta;
621 client_->DidOverscroll(rounded_overscroll_delta);
624 void BrowserViewRenderer::EnsureContinuousInvalidation(
625 bool force_invalidate,
626 bool skip_reschedule_tick) {
627 if (force_invalidate)
628 invalidate_after_composite_ = true;
630 // This method should be called again when any of these conditions change.
631 bool need_invalidate =
632 compositor_needs_continuous_invalidate_ || invalidate_after_composite_;
633 if (!need_invalidate || block_invalidates_)
636 if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_)
637 invalidate_after_composite_ = false;
639 // Always call view invalidate. We rely the Android framework to ignore the
640 // invalidate when it's not needed such as when view is not visible.
641 client_->PostInvalidate();
643 // Stop fallback ticks when one of these is true.
644 // 1) Webview is paused. Also need to check we are not in clear view since
645 // paused, offscreen still expect clear view to recover.
646 // 2) If we are attached to window and the window is not visible (eg when
647 // app is in the background). We are sure in this case the webview is used
648 // "on-screen" but that updates are not needed when in the background.
649 bool throttle_fallback_tick =
650 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
651 if (throttle_fallback_tick)
654 block_invalidates_ = compositor_needs_continuous_invalidate_;
655 if (skip_reschedule_tick && fallback_tick_pending_)
658 // Unretained here is safe because the callbacks are cancelled when
659 // they are destroyed.
660 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
661 base::Unretained(this)));
662 fallback_tick_fired_.Cancel();
663 fallback_tick_pending_ = false;
665 // No need to reschedule fallback tick if compositor does not need to be
666 // ticked. This can happen if this is reached because force_invalidate is
668 if (compositor_needs_continuous_invalidate_) {
669 fallback_tick_pending_ = true;
670 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
674 void BrowserViewRenderer::PostFallbackTick() {
675 DCHECK(fallback_tick_fired_.IsCancelled());
676 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
677 base::Unretained(this)));
678 if (compositor_needs_continuous_invalidate_) {
679 ui_task_runner_->PostDelayedTask(
681 fallback_tick_fired_.callback(),
682 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
684 // Pretend we just composited to unblock further invalidates.
689 void BrowserViewRenderer::FallbackTickFired() {
690 TRACE_EVENT1("android_webview",
691 "BrowserViewRenderer::FallbackTickFired",
692 "compositor_needs_continuous_invalidate_",
693 compositor_needs_continuous_invalidate_);
695 // This should only be called if OnDraw or DrawGL did not come in time, which
696 // means block_invalidates_ must still be true.
697 DCHECK(block_invalidates_);
698 fallback_tick_pending_ = false;
699 if (compositor_needs_continuous_invalidate_ && compositor_) {
700 if (hardware_enabled_) {
701 ReturnResourceFromParent();
702 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
703 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
705 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), true);
708 ForceFakeCompositeSW();
711 // Pretend we just composited to unblock further invalidates.
716 void BrowserViewRenderer::ForceFakeCompositeSW() {
719 bitmap.allocN32Pixels(1, 1);
720 bitmap.eraseColor(0);
721 SkCanvas canvas(bitmap);
722 CompositeSW(&canvas);
725 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
727 ReturnResourceFromParent();
728 bool result = compositor_->DemandDrawSw(canvas);
733 void BrowserViewRenderer::DidComposite() {
734 block_invalidates_ = false;
735 post_fallback_tick_.Cancel();
736 fallback_tick_fired_.Cancel();
737 fallback_tick_pending_ = false;
738 EnsureContinuousInvalidation(false, false);
741 void BrowserViewRenderer::DidSkipCompositeInDraw() {
742 block_invalidates_ = false;
743 EnsureContinuousInvalidation(true, true);
746 std::string BrowserViewRenderer::ToString() const {
748 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
749 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
750 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
751 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
752 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
753 base::StringAppendF(&str,
754 "compositor_needs_continuous_invalidate: %d ",
755 compositor_needs_continuous_invalidate_);
756 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
757 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
758 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
759 base::StringAppendF(&str,
760 "global visible rect: %s ",
761 last_on_draw_global_visible_rect_.ToString().c_str());
763 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
764 base::StringAppendF(&str,
765 "overscroll_rounding_error_: %s ",
766 overscroll_rounding_error_.ToString().c_str());
768 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
769 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
773 } // namespace android_webview