Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / android_webview / browser / browser_view_renderer.cc
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.
4
5 #include "android_webview/browser/browser_view_renderer.h"
6
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"
25
26 namespace android_webview {
27
28 namespace {
29
30 const int64 kFallbackTickTimeoutInMilliseconds = 100;
31
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;
37
38 }  // namespace
39
40 // static
41 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
42   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
43
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) {
48     base::StringToUint64(
49         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
50             switches::kForceGpuMemAvailableMb),
51         &g_memory_override_in_bytes);
52     g_memory_override_in_bytes *= 1024 * 1024;
53   }
54 }
55
56 BrowserViewRenderer::BrowserViewRenderer(
57     BrowserViewRendererClient* client,
58     content::WebContents* web_contents,
59     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
60     : client_(client),
61       shared_renderer_state_(ui_task_runner, this),
62       web_contents_(web_contents),
63       ui_task_runner_(ui_task_runner),
64       compositor_(NULL),
65       is_paused_(false),
66       view_visible_(false),
67       window_visible_(false),
68       attached_to_window_(false),
69       hardware_enabled_(false),
70       dip_scale_(0.0),
71       page_scale_factor_(1.0),
72       on_new_picture_enable_(false),
73       clear_view_(false),
74       compositor_needs_continuous_invalidate_(false),
75       invalidate_after_composite_(false),
76       block_invalidates_(false),
77       fallback_tick_pending_(false),
78       width_(0),
79       height_(0) {
80   CHECK(web_contents_);
81   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
82
83   // Currently the logic in this class relies on |compositor_| remaining
84   // NULL until the DidInitializeCompositor() call, hence it is not set here.
85 }
86
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.
91 }
92
93 intptr_t BrowserViewRenderer::GetAwDrawGLViewContext() {
94   return reinterpret_cast<intptr_t>(&shared_renderer_state_);
95 }
96
97 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
98   return client_->RequestDrawGL(wait_for_completion);
99 }
100
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.
105   enum {
106     TRIM_MEMORY_RUNNING_LOW = 10,
107     TRIM_MEMORY_UI_HIDDEN = 20,
108     TRIM_MEMORY_BACKGROUND = 40,
109     TRIM_MEMORY_MODERATE = 60,
110   };
111
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
114   // backgrounded.
115   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
116     return;
117
118   // Do not release resources on view we expect to get DrawGL soon.
119   if (level < TRIM_MEMORY_BACKGROUND && visible)
120     return;
121
122   // Nothing to drop.
123   if (!compositor_ || !hardware_enabled_)
124     return;
125
126   TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
127
128   // Drop everything in hardware.
129   if (level >= TRIM_MEMORY_MODERATE) {
130     shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
131     return;
132   }
133
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();
138 }
139
140 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
141   if (g_memory_override_in_bytes)
142     return static_cast<size_t>(g_memory_override_in_bytes);
143
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.
148   bytes_limit =
149       (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
150   return bytes_limit;
151 }
152
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;
159
160   if (clear_view_)
161     return false;
162
163   if (is_hardware_canvas && attached_to_window_ &&
164       !switches::ForceAuxiliaryBitmap()) {
165     return OnDrawHardware();
166   }
167
168   // Perform a software draw
169   return OnDrawSoftware(java_canvas);
170 }
171
172 bool BrowserViewRenderer::OnDrawHardware() {
173   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
174   shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
175   if (!compositor_)
176     return false;
177
178   shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
179
180   if (!hardware_enabled_) {
181     hardware_enabled_ = compositor_->InitializeHwDraw();
182   }
183   if (!hardware_enabled_)
184     return false;
185
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);
192     return true;
193   }
194
195   ReturnResourceFromParent();
196   if (shared_renderer_state_.HasCompositorFrameOnUI()) {
197     TRACE_EVENT_INSTANT0("android_webview",
198                          "EarlyOut_PreviousFrameUnconsumed",
199                          TRACE_EVENT_SCOPE_THREAD);
200     DidSkipCompositeInDraw();
201     return true;
202   }
203
204   scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
205   if (!frame.get())
206     return false;
207
208   shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
209   return true;
210 }
211
212 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() {
213   compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
214
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;
222
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;
230   } else {
231     viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
232   }
233
234   scoped_ptr<cc::CompositorFrame> frame =
235       compositor_->DemandDrawHw(surface_size,
236                                 gfx::Transform(),
237                                 viewport,
238                                 clip,
239                                 viewport_rect_for_tile_priority,
240                                 transform_for_tile_priority);
241   if (frame.get())
242     DidComposite();
243   return frame.Pass();
244 }
245
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);
256   }
257 }
258
259 void BrowserViewRenderer::ReturnUnusedResource(
260     scoped_ptr<cc::CompositorFrame> frame) {
261   if (!frame.get())
262     return;
263
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);
269 }
270
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);
276   }
277 }
278
279 void BrowserViewRenderer::DidSkipCommitFrame() {
280   // Treat it the same way as skipping onDraw.
281   DidSkipCompositeInDraw();
282 }
283
284 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
285   client_->InvalidateOnFunctorDestroy();
286 }
287
288 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) {
289   if (!compositor_) {
290     TRACE_EVENT_INSTANT0(
291         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
292     return false;
293   }
294
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
300   // bitmap.
301   return BrowserViewRendererJavaHelper::GetInstance()
302       ->RenderViaAuxilaryBitmapIfNeeded(
303           java_canvas,
304           last_on_draw_scroll_offset_,
305           gfx::Size(width_, height_),
306           base::Bind(&BrowserViewRenderer::CompositeSW,
307                      base::Unretained(this)));
308 }
309
310 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
311                                                             int height) {
312   TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
313
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());
319   }
320
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_,
324                                                gfx::Vector2dF());
325
326   SkPictureRecorder recorder;
327   SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
328   if (compositor_)
329     CompositeSW(rec_canvas);
330   return skia::AdoptRef(recorder.endRecording());
331 }
332
333 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
334   on_new_picture_enable_ = enabled;
335 }
336
337 void BrowserViewRenderer::ClearView() {
338   TRACE_EVENT_INSTANT0("android_webview",
339                        "BrowserViewRenderer::ClearView",
340                        TRACE_EVENT_SCOPE_THREAD);
341   if (clear_view_)
342     return;
343
344   clear_view_ = true;
345   // Always invalidate ignoring the compositor to actually clear the webview.
346   EnsureContinuousInvalidation(true, false);
347 }
348
349 void BrowserViewRenderer::SetIsPaused(bool paused) {
350   TRACE_EVENT_INSTANT1("android_webview",
351                        "BrowserViewRenderer::SetIsPaused",
352                        TRACE_EVENT_SCOPE_THREAD,
353                        "paused",
354                        paused);
355   is_paused_ = paused;
356   EnsureContinuousInvalidation(false, false);
357 }
358
359 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
360   TRACE_EVENT_INSTANT1("android_webview",
361                        "BrowserViewRenderer::SetViewVisibility",
362                        TRACE_EVENT_SCOPE_THREAD,
363                        "view_visible",
364                        view_visible);
365   view_visible_ = view_visible;
366 }
367
368 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
369   TRACE_EVENT_INSTANT1("android_webview",
370                        "BrowserViewRenderer::SetWindowVisibility",
371                        TRACE_EVENT_SCOPE_THREAD,
372                        "window_visible",
373                        window_visible);
374   window_visible_ = window_visible;
375   EnsureContinuousInvalidation(false, false);
376 }
377
378 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
379   TRACE_EVENT_INSTANT2("android_webview",
380                        "BrowserViewRenderer::OnSizeChanged",
381                        TRACE_EVENT_SCOPE_THREAD,
382                        "width",
383                        width,
384                        "height",
385                        height);
386   width_ = width;
387   height_ = height;
388 }
389
390 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
391   TRACE_EVENT2("android_webview",
392                "BrowserViewRenderer::OnAttachedToWindow",
393                "width",
394                width,
395                "height",
396                height);
397   attached_to_window_ = true;
398   width_ = width;
399   height_ = height;
400 }
401
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_);
407 }
408
409 void BrowserViewRenderer::ReleaseHardware() {
410   DCHECK(hardware_enabled_);
411   ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
412   ReturnResourceFromParent();
413   DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
414
415   if (compositor_) {
416     compositor_->ReleaseHwDraw();
417   }
418
419   hardware_enabled_ = false;
420 }
421
422 bool BrowserViewRenderer::IsVisible() const {
423   // Ignore |window_visible_| if |attached_to_window_| is false.
424   return view_visible_ && (!attached_to_window_ || window_visible_);
425 }
426
427 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
428   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
429 }
430
431 void BrowserViewRenderer::DidInitializeCompositor(
432     content::SynchronousCompositor* compositor) {
433   TRACE_EVENT0("android_webview",
434                "BrowserViewRenderer::DidInitializeCompositor");
435   DCHECK(compositor);
436   DCHECK(!compositor_);
437   compositor_ = compositor;
438 }
439
440 void BrowserViewRenderer::DidDestroyCompositor(
441     content::SynchronousCompositor* compositor) {
442   TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
443   DCHECK(compositor_);
444   compositor_ = NULL;
445 }
446
447 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
448   if (compositor_needs_continuous_invalidate_ == invalidate)
449     return;
450
451   TRACE_EVENT_INSTANT1("android_webview",
452                        "BrowserViewRenderer::SetContinuousInvalidate",
453                        TRACE_EVENT_SCOPE_THREAD,
454                        "invalidate",
455                        invalidate);
456   compositor_needs_continuous_invalidate_ = invalidate;
457
458   EnsureContinuousInvalidation(false, false);
459 }
460
461 void BrowserViewRenderer::SetDipScale(float dip_scale) {
462   dip_scale_ = dip_scale;
463   CHECK_GT(dip_scale_, 0);
464 }
465
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_));
470 }
471
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()) /
481                             max_offset.x());
482   }
483   if (max_offset.y()) {
484     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
485                             max_offset.y());
486   }
487
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());
492
493   if (scroll_offset_dip_ == scroll_offset_dip)
494     return;
495
496   scroll_offset_dip_ = scroll_offset_dip;
497
498   TRACE_EVENT_INSTANT2("android_webview",
499                "BrowserViewRenderer::ScrollTo",
500                TRACE_EVENT_SCOPE_THREAD,
501                "x",
502                scroll_offset_dip.x(),
503                "y",
504                scroll_offset_dip.y());
505
506   if (compositor_)
507     compositor_->DidChangeRootLayerScrollOffset();
508 }
509
510 void BrowserViewRenderer::DidUpdateContent() {
511   TRACE_EVENT_INSTANT0("android_webview",
512                        "BrowserViewRenderer::DidUpdateContent",
513                        TRACE_EVENT_SCOPE_THREAD);
514   clear_view_ = false;
515   if (on_new_picture_enable_)
516     client_->OnNewPicture();
517 }
518
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)
524     return;
525
526   scroll_offset_dip_ = scroll_offset_dip;
527
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());
535   }
536
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());
540   }
541
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());
546
547   client_->ScrollContainerViewTo(scroll_offset);
548 }
549
550 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
551   return scroll_offset_dip_;
552 }
553
554 bool BrowserViewRenderer::IsExternalFlingActive() const {
555   return client_->IsFlingActive();
556 }
557
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(
566       "android_webview",
567       "BrowserViewRenderer::UpdateRootLayerState",
568       TRACE_EVENT_SCOPE_THREAD,
569       "state",
570       RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
571
572   DCHECK_GT(dip_scale_, 0);
573
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());
577
578   page_scale_factor_ = page_scale_factor;
579   DCHECK_GT(page_scale_factor_, 0);
580
581   client_->UpdateScrollState(max_scroll_offset(),
582                              scrollable_size_dip,
583                              page_scale_factor,
584                              min_page_scale_factor,
585                              max_page_scale_factor);
586   SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
587 }
588
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();
595
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());
598
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());
601
602   state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
603   state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
604
605   state->SetDouble("page_scale_factor", page_scale_factor_);
606   return state;
607 }
608
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);
622 }
623
624 void BrowserViewRenderer::EnsureContinuousInvalidation(
625     bool force_invalidate,
626     bool skip_reschedule_tick) {
627   if (force_invalidate)
628     invalidate_after_composite_ = true;
629
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_)
634     return;
635
636   if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_)
637     invalidate_after_composite_ = false;
638
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();
642
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)
652     return;
653
654   block_invalidates_ = compositor_needs_continuous_invalidate_;
655   if (skip_reschedule_tick && fallback_tick_pending_)
656     return;
657
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;
664
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
667   // true.
668   if (compositor_needs_continuous_invalidate_) {
669     fallback_tick_pending_ = true;
670     ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
671   }
672 }
673
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(
680         FROM_HERE,
681         fallback_tick_fired_.callback(),
682         base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
683   } else {
684     // Pretend we just composited to unblock further invalidates.
685     DidComposite();
686   }
687 }
688
689 void BrowserViewRenderer::FallbackTickFired() {
690   TRACE_EVENT1("android_webview",
691                "BrowserViewRenderer::FallbackTickFired",
692                "compositor_needs_continuous_invalidate_",
693                compositor_needs_continuous_invalidate_);
694
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();
704       if (frame.get()) {
705         shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), true);
706       }
707     } else {
708       ForceFakeCompositeSW();
709     }
710   } else {
711     // Pretend we just composited to unblock further invalidates.
712     DidComposite();
713   }
714 }
715
716 void BrowserViewRenderer::ForceFakeCompositeSW() {
717   DCHECK(compositor_);
718   SkBitmap bitmap;
719   bitmap.allocN32Pixels(1, 1);
720   bitmap.eraseColor(0);
721   SkCanvas canvas(bitmap);
722   CompositeSW(&canvas);
723 }
724
725 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
726   DCHECK(compositor_);
727   ReturnResourceFromParent();
728   bool result = compositor_->DemandDrawSw(canvas);
729   DidComposite();
730   return result;
731 }
732
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);
739 }
740
741 void BrowserViewRenderer::DidSkipCompositeInDraw() {
742   block_invalidates_ = false;
743   EnsureContinuousInvalidation(true, true);
744 }
745
746 std::string BrowserViewRenderer::ToString() const {
747   std::string str;
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());
762   base::StringAppendF(
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());
767   base::StringAppendF(
768       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
769   base::StringAppendF(&str, "clear_view: %d ", clear_view_);
770   return str;
771 }
772
773 }  // namespace android_webview