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 "android_webview/public/browser/draw_gl.h"
11 #include "base/android/jni_android.h"
12 #include "base/auto_reset.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/json/json_writer.h"
16 #include "base/logging.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h"
19 #include "cc/output/compositor_frame.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/common/content_switches.h"
23 #include "gpu/command_buffer/service/gpu_switches.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "third_party/skia/include/core/SkCanvas.h"
26 #include "third_party/skia/include/core/SkPicture.h"
27 #include "third_party/skia/include/core/SkPictureRecorder.h"
28 #include "ui/gfx/vector2d_conversions.h"
30 using base::android::AttachCurrentThread;
31 using base::android::JavaRef;
32 using base::android::ScopedJavaLocalRef;
33 using content::BrowserThread;
34 using content::SynchronousCompositorMemoryPolicy;
36 namespace android_webview {
40 const int64 kFallbackTickTimeoutInMilliseconds = 100;
42 // Used to calculate memory allocation. Determined experimentally.
43 const size_t kMemoryMultiplier = 20;
44 const size_t kBytesPerPixel = 4;
45 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
46 uint64 g_memory_override_in_bytes = 0u;
48 // Used to calculate tile allocation. Determined experimentally.
49 const size_t kTileMultiplier = 12;
50 const size_t kTileAllocationStep = 20;
51 // This will be set by static function CalculateTileMemoryPolicy() during init.
52 // See AwMainDelegate::BasicStartupComplete.
55 class TracedValue : public base::debug::ConvertableToTraceFormat {
57 explicit TracedValue(base::Value* value) : value_(value) {}
58 static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue(
60 return scoped_refptr<base::debug::ConvertableToTraceFormat>(
61 new TracedValue(value));
63 virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
65 base::JSONWriter::Write(value_.get(), &tmp);
70 virtual ~TracedValue() {}
71 scoped_ptr<base::Value> value_;
73 DISALLOW_COPY_AND_ASSIGN(TracedValue);
79 void BrowserViewRenderer::CalculateTileMemoryPolicy(bool use_zero_copy) {
80 CommandLine* cl = CommandLine::ForCurrentProcess();
82 // If the value was overridden on the command line, use the specified value.
83 bool client_hard_limit_bytes_overridden =
84 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
85 if (client_hard_limit_bytes_overridden) {
87 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
88 switches::kForceGpuMemAvailableMb),
89 &g_memory_override_in_bytes);
90 g_memory_override_in_bytes *= 1024 * 1024;
94 // Use chrome's default tile size, which varies from 256 to 512.
95 // Be conservative here and use the smallest tile size possible.
96 g_tile_area = 256 * 256;
98 // Also use a high tile limit since there are no file descriptor issues.
99 GlobalTileManager::GetInstance()->SetTileLimit(1000);
103 const char kDefaultTileSize[] = "384";
105 if (!cl->HasSwitch(switches::kDefaultTileWidth))
106 cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
108 if (!cl->HasSwitch(switches::kDefaultTileHeight))
109 cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
112 base::StringToSizeT(kDefaultTileSize, &tile_size);
113 g_tile_area = tile_size * tile_size;
116 BrowserViewRenderer::BrowserViewRenderer(
117 BrowserViewRendererClient* client,
118 SharedRendererState* shared_renderer_state,
119 content::WebContents* web_contents,
120 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
122 shared_renderer_state_(shared_renderer_state),
123 web_contents_(web_contents),
124 ui_task_runner_(ui_task_runner),
127 view_visible_(false),
128 window_visible_(false),
129 attached_to_window_(false),
130 hardware_enabled_(false),
132 page_scale_factor_(1.0),
133 on_new_picture_enable_(false),
135 compositor_needs_continuous_invalidate_(false),
136 block_invalidates_(false),
139 CHECK(web_contents_);
140 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
142 // Currently the logic in this class relies on |compositor_| remaining
143 // NULL until the DidInitializeCompositor() call, hence it is not set here.
146 BrowserViewRenderer::~BrowserViewRenderer() {
147 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
148 // OnDetachedFromWindow should be called before the destructor, so the memory
149 // policy should have already been updated.
152 // This function updates the resource allocation in GlobalTileManager.
153 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155 // Constants from Android ComponentCallbacks2.
157 TRIM_MEMORY_RUNNING_LOW = 10,
158 TRIM_MEMORY_UI_HIDDEN = 20,
159 TRIM_MEMORY_BACKGROUND = 40,
162 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
163 // it does not indicate memory pressure, but merely that the app is
165 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
168 // Do not release resources on view we expect to get DrawGL soon.
169 if (level < TRIM_MEMORY_BACKGROUND && visible)
172 // Just set the memory limit to 0 and drop all tiles. This will be reset to
173 // normal levels in the next DrawGL call.
174 SynchronousCompositorMemoryPolicy zero_policy;
175 if (memory_policy_ == zero_policy)
178 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
180 RequestMemoryPolicy(zero_policy);
181 EnforceMemoryPolicyImmediately(zero_policy);
184 SynchronousCompositorMemoryPolicy
185 BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
186 SynchronousCompositorMemoryPolicy policy;
187 size_t width = last_on_draw_global_visible_rect_.width();
188 size_t height = last_on_draw_global_visible_rect_.height();
189 policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
190 // Round up to a multiple of kMemoryAllocationStep.
192 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
194 if (g_memory_override_in_bytes)
195 policy.bytes_limit = static_cast<size_t>(g_memory_override_in_bytes);
197 size_t tiles = width * height * kTileMultiplier / g_tile_area;
198 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
199 // is also kTileAllocationStep.
200 tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep;
201 policy.num_resources_limit = tiles;
205 // This function updates the cached memory policy in shared renderer state, as
206 // well as the tile resource allocation in GlobalTileManager.
207 void BrowserViewRenderer::RequestMemoryPolicy(
208 SynchronousCompositorMemoryPolicy& new_policy) {
209 GlobalTileManager* manager = GlobalTileManager::GetInstance();
211 // The following line will call BrowserViewRenderer::SetMemoryPolicy().
212 manager->RequestTiles(new_policy, tile_manager_key_);
215 void BrowserViewRenderer::SetMemoryPolicy(
216 SynchronousCompositorMemoryPolicy new_policy,
217 bool effective_immediately) {
218 memory_policy_ = new_policy;
219 if (effective_immediately)
220 EnforceMemoryPolicyImmediately(memory_policy_);
223 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
224 SynchronousCompositorMemoryPolicy new_policy) {
225 compositor_->SetMemoryPolicy(new_policy);
226 ForceFakeCompositeSW();
229 SynchronousCompositorMemoryPolicy BrowserViewRenderer::GetMemoryPolicy() const {
230 return memory_policy_;
233 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
234 bool is_hardware_canvas,
235 const gfx::Vector2d& scroll,
236 const gfx::Rect& global_visible_rect) {
237 last_on_draw_scroll_offset_ = scroll;
238 last_on_draw_global_visible_rect_ = global_visible_rect;
243 if (is_hardware_canvas && attached_to_window_ &&
244 !switches::ForceAuxiliaryBitmap()) {
245 return OnDrawHardware(java_canvas);
248 // Perform a software draw
249 return OnDrawSoftware(java_canvas);
252 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
253 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
257 if (last_on_draw_global_visible_rect_.IsEmpty()) {
258 TRACE_EVENT_INSTANT0("android_webview",
259 "EarlyOut_EmptyVisibleRect",
260 TRACE_EVENT_SCOPE_THREAD);
261 shared_renderer_state_->SetForceInvalidateOnNextDrawGL(true);
262 return client_->RequestDrawGL(java_canvas, false);
265 if (!hardware_enabled_) {
266 hardware_enabled_ = compositor_->InitializeHwDraw();
267 if (hardware_enabled_) {
268 tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
271 if (!hardware_enabled_)
274 ReturnResourceFromParent();
275 SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy();
276 RequestMemoryPolicy(new_policy);
277 compositor_->SetMemoryPolicy(memory_policy_);
279 if (shared_renderer_state_->HasDrawGLInput()) {
280 TRACE_EVENT_INSTANT0("android_webview",
281 "EarlyOut_PreviousFrameUnconsumed",
282 TRACE_EVENT_SCOPE_THREAD);
283 // TODO(boliu): Rename this method. We didn't actually composite here.
285 return client_->RequestDrawGL(java_canvas, false);
288 scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput);
289 draw_gl_input->scroll_offset = last_on_draw_scroll_offset_;
290 draw_gl_input->width = width_;
291 draw_gl_input->height = height_;
293 parent_draw_constraints_ = shared_renderer_state_->ParentDrawConstraints();
294 gfx::Size surface_size(width_, height_);
295 gfx::Rect viewport(surface_size);
296 gfx::Rect clip = viewport;
297 gfx::Transform transform_for_tile_priority =
298 parent_draw_constraints_.transform;
300 // If the WebView is on a layer, WebView does not know what transform is
301 // applied onto the layer so global visible rect does not make sense here.
302 // In this case, just use the surface rect for tiling.
303 gfx::Rect viewport_rect_for_tile_priority;
304 if (parent_draw_constraints_.is_layer)
305 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
307 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
309 scoped_ptr<cc::CompositorFrame> frame =
310 compositor_->DemandDrawHw(surface_size,
314 viewport_rect_for_tile_priority,
315 transform_for_tile_priority);
319 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_);
321 frame->AssignTo(&draw_gl_input->frame);
322 shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());
324 return client_->RequestDrawGL(java_canvas, false);
327 void BrowserViewRenderer::UpdateParentDrawConstraints() {
328 // Post an invalidate if the parent draw constraints are stale and there is
329 // no pending invalidate.
330 if (shared_renderer_state_->NeedsForceInvalidateOnNextDrawGL() ||
331 !parent_draw_constraints_.Equals(
332 shared_renderer_state_->ParentDrawConstraints())) {
333 shared_renderer_state_->SetForceInvalidateOnNextDrawGL(false);
334 EnsureContinuousInvalidation(true);
338 void BrowserViewRenderer::ReturnUnusedResource(scoped_ptr<DrawGLInput> input) {
342 cc::CompositorFrameAck frame_ack;
343 cc::TransferableResource::ReturnResources(
344 input->frame.delegated_frame_data->resource_list,
345 &frame_ack.resources);
346 if (!frame_ack.resources.empty())
347 compositor_->ReturnResources(frame_ack);
350 void BrowserViewRenderer::ReturnResourceFromParent() {
351 cc::CompositorFrameAck frame_ack;
352 shared_renderer_state_->SwapReturnedResources(&frame_ack.resources);
353 if (!frame_ack.resources.empty()) {
354 compositor_->ReturnResources(frame_ack);
358 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) {
360 TRACE_EVENT_INSTANT0(
361 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
365 // TODO(hush): right now webview size is passed in as the auxiliary bitmap
366 // size, which might hurt performace (only for software draws with auxiliary
367 // bitmap). For better performance, get global visible rect, transform it
368 // from screen space to view space, then intersect with the webview in
369 // viewspace. Use the resulting rect as the auxiliary
371 return BrowserViewRendererJavaHelper::GetInstance()
372 ->RenderViaAuxilaryBitmapIfNeeded(
374 last_on_draw_scroll_offset_,
375 gfx::Size(width_, height_),
376 base::Bind(&BrowserViewRenderer::CompositeSW,
377 base::Unretained(this)));
380 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
382 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
384 // Return empty Picture objects for empty SkPictures.
385 if (width <= 0 || height <= 0) {
386 SkPictureRecorder emptyRecorder;
387 emptyRecorder.beginRecording(0, 0);
388 return skia::AdoptRef(emptyRecorder.endRecording());
391 // Reset scroll back to the origin, will go back to the old
392 // value when scroll_reset is out of scope.
393 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
396 SkPictureRecorder recorder;
397 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
399 CompositeSW(rec_canvas);
400 return skia::AdoptRef(recorder.endRecording());
403 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
404 on_new_picture_enable_ = enabled;
407 void BrowserViewRenderer::ClearView() {
408 TRACE_EVENT_INSTANT0("android_webview",
409 "BrowserViewRenderer::ClearView",
410 TRACE_EVENT_SCOPE_THREAD);
415 // Always invalidate ignoring the compositor to actually clear the webview.
416 EnsureContinuousInvalidation(true);
419 void BrowserViewRenderer::SetIsPaused(bool paused) {
420 TRACE_EVENT_INSTANT1("android_webview",
421 "BrowserViewRenderer::SetIsPaused",
422 TRACE_EVENT_SCOPE_THREAD,
426 EnsureContinuousInvalidation(false);
429 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
430 TRACE_EVENT_INSTANT1("android_webview",
431 "BrowserViewRenderer::SetViewVisibility",
432 TRACE_EVENT_SCOPE_THREAD,
435 view_visible_ = view_visible;
438 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
439 TRACE_EVENT_INSTANT1("android_webview",
440 "BrowserViewRenderer::SetWindowVisibility",
441 TRACE_EVENT_SCOPE_THREAD,
444 window_visible_ = window_visible;
445 EnsureContinuousInvalidation(false);
448 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
449 TRACE_EVENT_INSTANT2("android_webview",
450 "BrowserViewRenderer::OnSizeChanged",
451 TRACE_EVENT_SCOPE_THREAD,
460 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
461 TRACE_EVENT2("android_webview",
462 "BrowserViewRenderer::OnAttachedToWindow",
467 attached_to_window_ = true;
472 void BrowserViewRenderer::OnDetachedFromWindow() {
473 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
474 attached_to_window_ = false;
475 DCHECK(!hardware_enabled_);
478 void BrowserViewRenderer::ReleaseHardware() {
479 DCHECK(hardware_enabled_);
480 ReturnUnusedResource(shared_renderer_state_->PassDrawGLInput());
481 ReturnResourceFromParent();
482 DCHECK(shared_renderer_state_->ReturnedResourcesEmpty());
484 compositor_->ReleaseHwDraw();
485 hardware_enabled_ = false;
487 SynchronousCompositorMemoryPolicy zero_policy;
488 RequestMemoryPolicy(zero_policy);
489 GlobalTileManager::GetInstance()->Remove(tile_manager_key_);
492 bool BrowserViewRenderer::IsVisible() const {
493 // Ignore |window_visible_| if |attached_to_window_| is false.
494 return view_visible_ && (!attached_to_window_ || window_visible_);
497 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
498 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
501 void BrowserViewRenderer::DidInitializeCompositor(
502 content::SynchronousCompositor* compositor) {
503 TRACE_EVENT0("android_webview",
504 "BrowserViewRenderer::DidInitializeCompositor");
506 DCHECK(!compositor_);
507 compositor_ = compositor;
510 void BrowserViewRenderer::DidDestroyCompositor(
511 content::SynchronousCompositor* compositor) {
512 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
515 SynchronousCompositorMemoryPolicy zero_policy;
516 DCHECK(memory_policy_ == zero_policy);
519 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
520 if (compositor_needs_continuous_invalidate_ == invalidate)
523 TRACE_EVENT_INSTANT1("android_webview",
524 "BrowserViewRenderer::SetContinuousInvalidate",
525 TRACE_EVENT_SCOPE_THREAD,
528 compositor_needs_continuous_invalidate_ = invalidate;
530 EnsureContinuousInvalidation(false);
533 void BrowserViewRenderer::SetDipScale(float dip_scale) {
534 dip_scale_ = dip_scale;
535 CHECK_GT(dip_scale_, 0);
538 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
539 DCHECK_GT(dip_scale_, 0);
540 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
541 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
544 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
545 gfx::Vector2d max_offset = max_scroll_offset();
546 gfx::Vector2dF scroll_offset_dip;
547 // To preserve the invariant that scrolling to the maximum physical pixel
548 // value also scrolls to the maximum dip pixel value we transform the physical
549 // offset into the dip offset by using a proportion (instead of dividing by
550 // dip_scale * page_scale_factor).
551 if (max_offset.x()) {
552 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
555 if (max_offset.y()) {
556 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
560 DCHECK_LE(0, scroll_offset_dip.x());
561 DCHECK_LE(0, scroll_offset_dip.y());
562 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
563 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
565 if (scroll_offset_dip_ == scroll_offset_dip)
568 scroll_offset_dip_ = scroll_offset_dip;
570 TRACE_EVENT_INSTANT2("android_webview",
571 "BrowserViewRenderer::ScrollTo",
572 TRACE_EVENT_SCOPE_THREAD,
574 scroll_offset_dip.x(),
576 scroll_offset_dip.y());
579 compositor_->DidChangeRootLayerScrollOffset();
582 void BrowserViewRenderer::DidUpdateContent() {
583 TRACE_EVENT_INSTANT0("android_webview",
584 "BrowserViewRenderer::DidUpdateContent",
585 TRACE_EVENT_SCOPE_THREAD);
587 if (on_new_picture_enable_)
588 client_->OnNewPicture();
591 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
592 gfx::Vector2dF scroll_offset_dip) {
593 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
594 // DrawGl when http://crbug.com/249972 is fixed.
595 if (scroll_offset_dip_ == scroll_offset_dip)
598 scroll_offset_dip_ = scroll_offset_dip;
600 gfx::Vector2d max_offset = max_scroll_offset();
601 gfx::Vector2d scroll_offset;
602 // For an explanation as to why this is done this way see the comment in
603 // BrowserViewRenderer::ScrollTo.
604 if (max_scroll_offset_dip_.x()) {
605 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
606 max_scroll_offset_dip_.x());
609 if (max_scroll_offset_dip_.y()) {
610 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
611 max_scroll_offset_dip_.y());
614 DCHECK_LE(0, scroll_offset.x());
615 DCHECK_LE(0, scroll_offset.y());
616 DCHECK_LE(scroll_offset.x(), max_offset.x());
617 DCHECK_LE(scroll_offset.y(), max_offset.y());
619 client_->ScrollContainerViewTo(scroll_offset);
622 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
623 return scroll_offset_dip_;
626 bool BrowserViewRenderer::IsExternalFlingActive() const {
627 return client_->IsFlingActive();
630 void BrowserViewRenderer::UpdateRootLayerState(
631 const gfx::Vector2dF& total_scroll_offset_dip,
632 const gfx::Vector2dF& max_scroll_offset_dip,
633 const gfx::SizeF& scrollable_size_dip,
634 float page_scale_factor,
635 float min_page_scale_factor,
636 float max_page_scale_factor) {
637 TRACE_EVENT_INSTANT1(
639 "BrowserViewRenderer::UpdateRootLayerState",
640 TRACE_EVENT_SCOPE_THREAD,
642 TracedValue::FromValue(
643 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip)
646 DCHECK_GT(dip_scale_, 0);
648 max_scroll_offset_dip_ = max_scroll_offset_dip;
649 DCHECK_LE(0, max_scroll_offset_dip_.x());
650 DCHECK_LE(0, max_scroll_offset_dip_.y());
652 page_scale_factor_ = page_scale_factor;
653 DCHECK_GT(page_scale_factor_, 0);
655 client_->UpdateScrollState(max_scroll_offset(),
658 min_page_scale_factor,
659 max_page_scale_factor);
660 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
663 scoped_ptr<base::Value> BrowserViewRenderer::RootLayerStateAsValue(
664 const gfx::Vector2dF& total_scroll_offset_dip,
665 const gfx::SizeF& scrollable_size_dip) {
666 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
668 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
669 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
671 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
672 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
674 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
675 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
677 state->SetDouble("page_scale_factor", page_scale_factor_);
678 return state.PassAs<base::Value>();
681 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
682 gfx::Vector2dF latest_overscroll_delta,
683 gfx::Vector2dF current_fling_velocity) {
684 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
685 if (accumulated_overscroll == latest_overscroll_delta)
686 overscroll_rounding_error_ = gfx::Vector2dF();
687 gfx::Vector2dF scaled_overscroll_delta =
688 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
689 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
690 scaled_overscroll_delta + overscroll_rounding_error_);
691 overscroll_rounding_error_ =
692 scaled_overscroll_delta - rounded_overscroll_delta;
693 client_->DidOverscroll(rounded_overscroll_delta);
696 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
697 // This method should be called again when any of these conditions change.
698 bool need_invalidate =
699 compositor_needs_continuous_invalidate_ || force_invalidate;
700 if (!need_invalidate || block_invalidates_)
703 // Always call view invalidate. We rely the Android framework to ignore the
704 // invalidate when it's not needed such as when view is not visible.
705 client_->PostInvalidate();
707 // Stop fallback ticks when one of these is true.
708 // 1) Webview is paused. Also need to check we are not in clear view since
709 // paused, offscreen still expect clear view to recover.
710 // 2) If we are attached to window and the window is not visible (eg when
711 // app is in the background). We are sure in this case the webview is used
712 // "on-screen" but that updates are not needed when in the background.
713 bool throttle_fallback_tick =
714 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
715 if (throttle_fallback_tick)
718 block_invalidates_ = compositor_needs_continuous_invalidate_;
720 // Unretained here is safe because the callbacks are cancelled when
721 // they are destroyed.
722 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
723 base::Unretained(this)));
724 fallback_tick_fired_.Cancel();
726 // No need to reschedule fallback tick if compositor does not need to be
727 // ticked. This can happen if this is reached because force_invalidate is
729 if (compositor_needs_continuous_invalidate_)
730 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
733 void BrowserViewRenderer::PostFallbackTick() {
734 DCHECK(fallback_tick_fired_.IsCancelled());
735 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
736 base::Unretained(this)));
737 if (compositor_needs_continuous_invalidate_) {
738 ui_task_runner_->PostDelayedTask(
740 fallback_tick_fired_.callback(),
741 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
743 // Pretend we just composited to unblock further invalidates.
748 void BrowserViewRenderer::FallbackTickFired() {
749 TRACE_EVENT1("android_webview",
750 "BrowserViewRenderer::FallbackTickFired",
751 "compositor_needs_continuous_invalidate_",
752 compositor_needs_continuous_invalidate_);
754 // This should only be called if OnDraw or DrawGL did not come in time, which
755 // means block_invalidates_ must still be true.
756 DCHECK(block_invalidates_);
757 if (compositor_needs_continuous_invalidate_ && compositor_) {
758 ForceFakeCompositeSW();
760 // Pretend we just composited to unblock further invalidates.
765 void BrowserViewRenderer::ForceFakeCompositeSW() {
768 bitmap.allocN32Pixels(1, 1);
769 bitmap.eraseColor(0);
770 SkCanvas canvas(bitmap);
771 CompositeSW(&canvas);
774 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
776 ReturnResourceFromParent();
777 bool result = compositor_->DemandDrawSw(canvas);
782 void BrowserViewRenderer::DidComposite() {
783 block_invalidates_ = false;
784 post_fallback_tick_.Cancel();
785 fallback_tick_fired_.Cancel();
786 EnsureContinuousInvalidation(false);
789 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
791 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
792 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
793 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
794 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
795 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
796 base::StringAppendF(&str,
797 "compositor_needs_continuous_invalidate: %d ",
798 compositor_needs_continuous_invalidate_);
799 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
800 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
801 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
802 base::StringAppendF(&str,
803 "global visible rect: %s ",
804 last_on_draw_global_visible_rect_.ToString().c_str());
806 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
807 base::StringAppendF(&str,
808 "overscroll_rounding_error_: %s ",
809 overscroll_rounding_error_.ToString().c_str());
811 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
812 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
814 base::StringAppendF(&str,
815 "clip left top right bottom: [%d %d %d %d] ",
816 draw_info->clip_left,
818 draw_info->clip_right,
819 draw_info->clip_bottom);
820 base::StringAppendF(&str,
821 "surface width height: [%d %d] ",
824 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
829 } // namespace android_webview