Upstream version 7.36.149.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/public/browser/draw_gl.h"
10 #include "base/android/jni_android.h"
11 #include "base/auto_reset.h"
12 #include "base/command_line.h"
13 #include "base/debug/trace_event.h"
14 #include "base/logging.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "content/public/browser/android/synchronous_compositor.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/content_switches.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "third_party/skia/include/core/SkPicture.h"
24 #include "third_party/skia/include/core/SkPictureRecorder.h"
25 #include "ui/gfx/vector2d_conversions.h"
26
27 using base::android::AttachCurrentThread;
28 using base::android::JavaRef;
29 using base::android::ScopedJavaLocalRef;
30 using content::BrowserThread;
31 using content::SynchronousCompositorMemoryPolicy;
32
33 namespace android_webview {
34
35 namespace {
36
37 const int64 kFallbackTickTimeoutInMilliseconds = 20;
38
39 // Used to calculate memory allocation. Determined experimentally.
40 const size_t kMemoryMultiplier = 10;
41 const size_t kBytesPerPixel = 4;
42 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
43
44 // Used to calculate tile allocation. Determined experimentally.
45 const size_t kTileMultiplier = 12;
46 const size_t kTileAllocationStep = 20;
47 // This will be set by static function CalculateTileMemoryPolicy() during init.
48 // See AwMainDelegate::BasicStartupComplete.
49 size_t g_tile_area;
50
51 class AutoResetWithLock {
52  public:
53   AutoResetWithLock(gfx::Vector2dF* scoped_variable,
54                     gfx::Vector2dF new_value,
55                     base::Lock& lock)
56       : scoped_variable_(scoped_variable),
57         original_value_(*scoped_variable),
58         lock_(lock) {
59     base::AutoLock auto_lock(lock_);
60     *scoped_variable_ = new_value;
61   }
62
63   ~AutoResetWithLock() {
64     base::AutoLock auto_lock(lock_);
65     *scoped_variable_ = original_value_;
66   }
67
68  private:
69   gfx::Vector2dF* scoped_variable_;
70   gfx::Vector2dF original_value_;
71   base::Lock& lock_;
72
73   DISALLOW_COPY_AND_ASSIGN(AutoResetWithLock);
74 };
75
76 }  // namespace
77
78 // static
79 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
80   CommandLine* cl = CommandLine::ForCurrentProcess();
81   const char kDefaultTileSize[] = "384";
82
83   if (!cl->HasSwitch(switches::kDefaultTileWidth))
84     cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
85
86   if (!cl->HasSwitch(switches::kDefaultTileHeight))
87     cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
88
89   size_t tile_size;
90   base::StringToSizeT(kDefaultTileSize, &tile_size);
91   g_tile_area = tile_size * tile_size;
92 }
93
94 BrowserViewRenderer::BrowserViewRenderer(
95     BrowserViewRendererClient* client,
96     SharedRendererState* shared_renderer_state,
97     content::WebContents* web_contents,
98     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
99     : client_(client),
100       shared_renderer_state_(shared_renderer_state),
101       web_contents_(web_contents),
102       weak_factory_on_ui_thread_(this),
103       ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()),
104       ui_task_runner_(ui_task_runner),
105       has_compositor_(false),
106       is_paused_(false),
107       view_visible_(false),
108       window_visible_(false),
109       attached_to_window_(false),
110       dip_scale_(0.0),
111       page_scale_factor_(1.0),
112       on_new_picture_enable_(false),
113       clear_view_(false),
114       compositor_needs_continuous_invalidate_(false),
115       block_invalidates_(false),
116       width_(0),
117       height_(0),
118       num_tiles_(0u),
119       num_bytes_(0u) {
120   CHECK(web_contents_);
121   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
122
123   // Currently the logic in this class relies on |has_compositor_| remaining
124   // false until the DidInitializeCompositor() call, hence it is not set here.
125 }
126
127 BrowserViewRenderer::~BrowserViewRenderer() {
128   content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
129   // OnDetachedFromWindow should be called before the destructor, so the memory
130   // policy should have already been updated.
131 }
132
133 // This function updates the cached memory policy in shared renderer state, as
134 // well as the tile resource allocation in GlobalTileManager.
135 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137   // Constants from Android ComponentCallbacks2.
138   enum {
139     TRIM_MEMORY_RUNNING_LOW = 10,
140     TRIM_MEMORY_UI_HIDDEN = 20,
141     TRIM_MEMORY_BACKGROUND = 40,
142   };
143
144   // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
145   // it does not indicate memory pressure, but merely that the app is
146   // backgrounded.
147   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
148     return;
149
150   // Do not release resources on view we expect to get DrawGL soon.
151   if (level < TRIM_MEMORY_BACKGROUND && visible)
152     return;
153
154   // Just set the memory limit to 0 and drop all tiles. This will be reset to
155   // normal levels in the next DrawGL call.
156   SynchronousCompositorMemoryPolicy zero_policy;
157   if (shared_renderer_state_->GetMemoryPolicy() == zero_policy)
158     return;
159
160   TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
161
162   RequestMemoryPolicy(zero_policy);
163   EnforceMemoryPolicyImmediately(zero_policy);
164 }
165
166 SynchronousCompositorMemoryPolicy
167 BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
168   SynchronousCompositorMemoryPolicy policy;
169   size_t width = draw_gl_input_.global_visible_rect.width();
170   size_t height = draw_gl_input_.global_visible_rect.height();
171   policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
172   // Round up to a multiple of kMemoryAllocationStep.
173   policy.bytes_limit =
174       (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
175
176   size_t tiles = width * height * kTileMultiplier / g_tile_area;
177   // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
178   // is also kTileAllocationStep.
179   tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep;
180   policy.num_resources_limit = tiles;
181   return policy;
182 }
183
184 // This function updates the cached memory policy in shared renderer state, as
185 // well as the tile resource allocation in GlobalTileManager.
186 void BrowserViewRenderer::RequestMemoryPolicy(
187     SynchronousCompositorMemoryPolicy& new_policy) {
188   // This will be used in SetNumTiles.
189   num_bytes_ = new_policy.bytes_limit;
190
191   GlobalTileManager* manager = GlobalTileManager::GetInstance();
192
193   // The following line will call BrowserViewRenderer::SetTilesNum().
194   manager->RequestTiles(new_policy.num_resources_limit, tile_manager_key_);
195 }
196
197 void BrowserViewRenderer::SetNumTiles(size_t num_tiles,
198                                       bool effective_immediately) {
199   if (num_tiles == num_tiles_)
200     return;
201   num_tiles_ = num_tiles;
202
203   SynchronousCompositorMemoryPolicy new_policy;
204   new_policy.num_resources_limit = num_tiles_;
205   new_policy.bytes_limit = num_bytes_;
206   shared_renderer_state_->SetMemoryPolicy(new_policy);
207
208   if (effective_immediately)
209     EnforceMemoryPolicyImmediately(new_policy);
210 }
211
212 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
213     SynchronousCompositorMemoryPolicy new_policy) {
214   shared_renderer_state_->GetCompositor()->SetMemoryPolicy(new_policy);
215   ForceFakeCompositeSW();
216   shared_renderer_state_->SetMemoryPolicyDirty(false);
217 }
218
219 size_t BrowserViewRenderer::GetNumTiles() const {
220   return shared_renderer_state_->GetMemoryPolicy().num_resources_limit;
221 }
222
223 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
224                                  bool is_hardware_canvas,
225                                  const gfx::Vector2d& scroll,
226                                  const gfx::Rect& global_visible_rect,
227                                  const gfx::Rect& clip) {
228   draw_gl_input_.frame_id++;
229   draw_gl_input_.scroll_offset = scroll;
230   draw_gl_input_.global_visible_rect = global_visible_rect;
231   draw_gl_input_.width = width_;
232   draw_gl_input_.height = height_;
233   if (clear_view_)
234     return false;
235   if (is_hardware_canvas && attached_to_window_) {
236     shared_renderer_state_->SetDrawGLInput(draw_gl_input_);
237
238     SynchronousCompositorMemoryPolicy old_policy =
239         shared_renderer_state_->GetMemoryPolicy();
240     SynchronousCompositorMemoryPolicy new_policy =
241         CalculateDesiredMemoryPolicy();
242     RequestMemoryPolicy(new_policy);
243     // We should be performing a hardware draw here. If we don't have the
244     // compositor yet or if RequestDrawGL fails, it means we failed this draw
245     // and thus return false here to clear to background color for this draw.
246     bool did_draw_gl =
247         has_compositor_ && client_->RequestDrawGL(java_canvas, false);
248     if (did_draw_gl)
249       GlobalTileManager::GetInstance()->DidUse(tile_manager_key_);
250     else
251       RequestMemoryPolicy(old_policy);
252
253     return did_draw_gl;
254   }
255   // Perform a software draw
256   return DrawSWInternal(java_canvas, clip);
257 }
258
259 void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) {
260   DidComposite(!result.clip_contains_visible_rect);
261 }
262
263 bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas,
264                                          const gfx::Rect& clip) {
265   if (clip.IsEmpty()) {
266     TRACE_EVENT_INSTANT0(
267         "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
268     return true;
269   }
270
271   if (!has_compositor_) {
272     TRACE_EVENT_INSTANT0(
273         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
274     return false;
275   }
276
277   return BrowserViewRendererJavaHelper::GetInstance()
278       ->RenderViaAuxilaryBitmapIfNeeded(
279             java_canvas,
280             draw_gl_input_.scroll_offset,
281             clip,
282             base::Bind(&BrowserViewRenderer::CompositeSW,
283                        base::Unretained(this)));
284 }
285
286 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
287                                                             int height) {
288   TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
289
290   // Return empty Picture objects for empty SkPictures.
291   if (width <= 0 || height <= 0) {
292     return skia::AdoptRef(new SkPicture);
293   }
294
295   // Reset scroll back to the origin, will go back to the old
296   // value when scroll_reset is out of scope.
297   AutoResetWithLock scroll_reset(
298       &scroll_offset_dip_, gfx::Vector2dF(), render_thread_lock_);
299
300   SkPictureRecorder recorder;
301   SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
302   if (has_compositor_)
303     CompositeSW(rec_canvas);
304   return skia::AdoptRef(recorder.endRecording());
305 }
306
307 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
308   on_new_picture_enable_ = enabled;
309 }
310
311 void BrowserViewRenderer::ClearView() {
312   TRACE_EVENT_INSTANT0("android_webview",
313                        "BrowserViewRenderer::ClearView",
314                        TRACE_EVENT_SCOPE_THREAD);
315   if (clear_view_)
316     return;
317
318   clear_view_ = true;
319   // Always invalidate ignoring the compositor to actually clear the webview.
320   EnsureContinuousInvalidation(true);
321 }
322
323 void BrowserViewRenderer::SetIsPaused(bool paused) {
324   TRACE_EVENT_INSTANT1("android_webview",
325                        "BrowserViewRenderer::SetIsPaused",
326                        TRACE_EVENT_SCOPE_THREAD,
327                        "paused",
328                        paused);
329   is_paused_ = paused;
330   EnsureContinuousInvalidation(false);
331 }
332
333 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
334   TRACE_EVENT_INSTANT1("android_webview",
335                        "BrowserViewRenderer::SetViewVisibility",
336                        TRACE_EVENT_SCOPE_THREAD,
337                        "view_visible",
338                        view_visible);
339   view_visible_ = view_visible;
340 }
341
342 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
343   TRACE_EVENT_INSTANT1("android_webview",
344                        "BrowserViewRenderer::SetWindowVisibility",
345                        TRACE_EVENT_SCOPE_THREAD,
346                        "window_visible",
347                        window_visible);
348   window_visible_ = window_visible;
349   EnsureContinuousInvalidation(false);
350 }
351
352 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
353   TRACE_EVENT_INSTANT2("android_webview",
354                        "BrowserViewRenderer::OnSizeChanged",
355                        TRACE_EVENT_SCOPE_THREAD,
356                        "width",
357                        width,
358                        "height",
359                        height);
360   width_ = width;
361   height_ = height;
362 }
363
364 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
365   TRACE_EVENT2("android_webview",
366                "BrowserViewRenderer::OnAttachedToWindow",
367                "width",
368                width,
369                "height",
370                height);
371   attached_to_window_ = true;
372   width_ = width;
373   height_ = height;
374   tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
375 }
376
377 void BrowserViewRenderer::OnDetachedFromWindow() {
378   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
379   attached_to_window_ = false;
380   SynchronousCompositorMemoryPolicy zero_policy;
381   RequestMemoryPolicy(zero_policy);
382   GlobalTileManager::GetInstance()->Remove(tile_manager_key_);
383   // The hardware resources are released in the destructor of hardware renderer,
384   // so we don't need to do it here.
385   // See AwContents::ReleaseHardwareDrawOnRenderThread(JNIEnv*, jobject).
386 }
387
388 bool BrowserViewRenderer::IsAttachedToWindow() const {
389   return attached_to_window_;
390 }
391
392 bool BrowserViewRenderer::IsVisible() const {
393   // Ignore |window_visible_| if |attached_to_window_| is false.
394   return view_visible_ && (!attached_to_window_ || window_visible_);
395 }
396
397 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
398   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
399 }
400
401 void BrowserViewRenderer::DidInitializeCompositor(
402     content::SynchronousCompositor* compositor) {
403   TRACE_EVENT0("android_webview",
404                "BrowserViewRenderer::DidInitializeCompositor");
405   DCHECK(compositor);
406   DCHECK(!has_compositor_);
407   DCHECK(ui_task_runner_->BelongsToCurrentThread());
408   has_compositor_ = true;
409   shared_renderer_state_->SetCompositorOnUiThread(compositor);
410 }
411
412 void BrowserViewRenderer::DidDestroyCompositor(
413     content::SynchronousCompositor* compositor) {
414   TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
415   DCHECK(has_compositor_);
416   DCHECK(ui_task_runner_->BelongsToCurrentThread());
417   has_compositor_ = false;
418   shared_renderer_state_->SetCompositorOnUiThread(NULL);
419   SynchronousCompositorMemoryPolicy zero_policy;
420   DCHECK(shared_renderer_state_->GetMemoryPolicy() == zero_policy);
421 }
422
423 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
424   {
425     base::AutoLock lock(render_thread_lock_);
426     if (compositor_needs_continuous_invalidate_ == invalidate)
427       return;
428
429     TRACE_EVENT_INSTANT1("android_webview",
430                          "BrowserViewRenderer::SetContinuousInvalidate",
431                          TRACE_EVENT_SCOPE_THREAD,
432                          "invalidate",
433                          invalidate);
434     compositor_needs_continuous_invalidate_ = invalidate;
435   }
436
437   if (ui_task_runner_->BelongsToCurrentThread()) {
438     EnsureContinuousInvalidation(false);
439     return;
440   }
441   ui_task_runner_->PostTask(
442       FROM_HERE,
443       base::Bind(&BrowserViewRenderer::EnsureContinuousInvalidation,
444                  ui_thread_weak_ptr_,
445                  false));
446 }
447
448 void BrowserViewRenderer::SetDipScale(float dip_scale) {
449   dip_scale_ = dip_scale;
450   CHECK(dip_scale_ > 0);
451 }
452
453 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
454   DCHECK_GT(dip_scale_, 0);
455   return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
456       max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
457 }
458
459 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
460   gfx::Vector2d max_offset = max_scroll_offset();
461   gfx::Vector2dF scroll_offset_dip;
462   // To preserve the invariant that scrolling to the maximum physical pixel
463   // value also scrolls to the maximum dip pixel value we transform the physical
464   // offset into the dip offset by using a proportion (instead of dividing by
465   // dip_scale * page_scale_factor).
466   if (max_offset.x()) {
467     scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
468                             max_offset.x());
469   }
470   if (max_offset.y()) {
471     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
472                             max_offset.y());
473   }
474
475   DCHECK_LE(0, scroll_offset_dip.x());
476   DCHECK_LE(0, scroll_offset_dip.y());
477   DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
478   DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
479
480   {
481     base::AutoLock lock(render_thread_lock_);
482     if (scroll_offset_dip_ == scroll_offset_dip)
483       return;
484
485     scroll_offset_dip_ = scroll_offset_dip;
486   }
487
488   if (has_compositor_)
489     shared_renderer_state_->GetCompositor()->
490         DidChangeRootLayerScrollOffset();
491 }
492
493 void BrowserViewRenderer::DidUpdateContent() {
494   if (!ui_task_runner_->BelongsToCurrentThread()) {
495     ui_task_runner_->PostTask(FROM_HERE,
496                               base::Bind(&BrowserViewRenderer::DidUpdateContent,
497                                          ui_thread_weak_ptr_));
498     return;
499   }
500   TRACE_EVENT_INSTANT0("android_webview",
501                        "BrowserViewRenderer::DidUpdateContent",
502                        TRACE_EVENT_SCOPE_THREAD);
503   clear_view_ = false;
504   if (on_new_picture_enable_)
505     client_->OnNewPicture();
506 }
507
508 void BrowserViewRenderer::SetMaxRootLayerScrollOffset(
509     gfx::Vector2dF new_value_dip) {
510   if (!ui_task_runner_->BelongsToCurrentThread()) {
511     ui_task_runner_->PostTask(
512         FROM_HERE,
513         base::Bind(&BrowserViewRenderer::SetMaxRootLayerScrollOffset,
514                    ui_thread_weak_ptr_,
515                    new_value_dip));
516     return;
517   }
518   DCHECK_GT(dip_scale_, 0);
519
520   max_scroll_offset_dip_ = new_value_dip;
521   DCHECK_LE(0, max_scroll_offset_dip_.x());
522   DCHECK_LE(0, max_scroll_offset_dip_.y());
523
524   client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
525 }
526
527 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
528     gfx::Vector2dF scroll_offset_dip) {
529   if (!ui_task_runner_->BelongsToCurrentThread()) {
530     ui_task_runner_->PostTask(
531         FROM_HERE,
532         base::Bind(&BrowserViewRenderer::SetTotalRootLayerScrollOffset,
533                    ui_thread_weak_ptr_,
534                    scroll_offset_dip));
535     return;
536   }
537
538   {
539     base::AutoLock lock(render_thread_lock_);
540     // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
541     // DrawGl when http://crbug.com/249972 is fixed.
542     if (scroll_offset_dip_ == scroll_offset_dip)
543       return;
544
545     scroll_offset_dip_ = scroll_offset_dip;
546   }
547
548   gfx::Vector2d max_offset = max_scroll_offset();
549   gfx::Vector2d scroll_offset;
550   // For an explanation as to why this is done this way see the comment in
551   // BrowserViewRenderer::ScrollTo.
552   if (max_scroll_offset_dip_.x()) {
553     scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
554                         max_scroll_offset_dip_.x());
555   }
556
557   if (max_scroll_offset_dip_.y()) {
558     scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
559                         max_scroll_offset_dip_.y());
560   }
561
562   DCHECK(0 <= scroll_offset.x());
563   DCHECK(0 <= scroll_offset.y());
564   // Disabled because the conditions are being violated while running
565   // AwZoomTest.testMagnification, see http://crbug.com/340648
566   // DCHECK(scroll_offset.x() <= max_offset.x());
567   // DCHECK(scroll_offset.y() <= max_offset.y());
568
569   client_->ScrollContainerViewTo(scroll_offset);
570 }
571
572 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
573   base::AutoLock lock(render_thread_lock_);
574   return scroll_offset_dip_;
575 }
576
577 bool BrowserViewRenderer::IsExternalFlingActive() const {
578   if (!ui_task_runner_->BelongsToCurrentThread()) {
579     // TODO(boliu): This is short term hack since we cannot call into
580     // view system on non-UI thread.
581     return false;
582   }
583   return client_->IsFlingActive();
584 }
585
586 void BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits(
587     float page_scale_factor,
588     float min_page_scale_factor,
589     float max_page_scale_factor) {
590   if (!ui_task_runner_->BelongsToCurrentThread()) {
591     ui_task_runner_->PostTask(
592         FROM_HERE,
593         base::Bind(&BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits,
594                    ui_thread_weak_ptr_,
595                    page_scale_factor,
596                    min_page_scale_factor,
597                    max_page_scale_factor));
598     return;
599   }
600   page_scale_factor_ = page_scale_factor;
601   DCHECK_GT(page_scale_factor_, 0);
602   client_->SetPageScaleFactorAndLimits(
603       page_scale_factor, min_page_scale_factor, max_page_scale_factor);
604   client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
605 }
606
607 void BrowserViewRenderer::SetRootLayerScrollableSize(
608     gfx::SizeF scrollable_size) {
609   if (!ui_task_runner_->BelongsToCurrentThread()) {
610     ui_task_runner_->PostTask(
611         FROM_HERE,
612         base::Bind(&BrowserViewRenderer::SetRootLayerScrollableSize,
613                    ui_thread_weak_ptr_,
614                    scrollable_size));
615     return;
616   }
617   client_->SetContentsSize(scrollable_size);
618 }
619
620 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
621                                         gfx::Vector2dF latest_overscroll_delta,
622                                         gfx::Vector2dF current_fling_velocity) {
623   if (!ui_task_runner_->BelongsToCurrentThread()) {
624     ui_task_runner_->PostTask(
625         FROM_HERE,
626         base::Bind(&BrowserViewRenderer::DidOverscroll,
627                    ui_thread_weak_ptr_,
628                    accumulated_overscroll,
629                    latest_overscroll_delta,
630                    current_fling_velocity));
631     return;
632   }
633   const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
634   if (accumulated_overscroll == latest_overscroll_delta)
635     overscroll_rounding_error_ = gfx::Vector2dF();
636   gfx::Vector2dF scaled_overscroll_delta =
637       gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
638   gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
639       scaled_overscroll_delta + overscroll_rounding_error_);
640   overscroll_rounding_error_ =
641       scaled_overscroll_delta - rounded_overscroll_delta;
642   client_->DidOverscroll(rounded_overscroll_delta);
643 }
644
645 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
646   // This method should be called again when any of these conditions change.
647   bool need_invalidate =
648       compositor_needs_continuous_invalidate_ || force_invalidate;
649   if (!need_invalidate || block_invalidates_)
650     return;
651
652   // Always call view invalidate. We rely the Android framework to ignore the
653   // invalidate when it's not needed such as when view is not visible.
654   client_->PostInvalidate();
655
656   // Stop fallback ticks when one of these is true.
657   // 1) Webview is paused. Also need to check we are not in clear view since
658   // paused, offscreen still expect clear view to recover.
659   // 2) If we are attached to window and the window is not visible (eg when
660   // app is in the background). We are sure in this case the webview is used
661   // "on-screen" but that updates are not needed when in the background.
662   bool throttle_fallback_tick =
663       (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
664   if (throttle_fallback_tick)
665     return;
666
667   block_invalidates_ = compositor_needs_continuous_invalidate_;
668
669   // Unretained here is safe because the callback is cancelled when
670   // |fallback_tick_| is destroyed.
671   fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
672                                   base::Unretained(this)));
673
674   // No need to reschedule fallback tick if compositor does not need to be
675   // ticked. This can happen if this is reached because force_invalidate is
676   // true.
677   if (compositor_needs_continuous_invalidate_) {
678     ui_task_runner_->PostDelayedTask(
679         FROM_HERE,
680         fallback_tick_.callback(),
681         base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
682   }
683 }
684
685 void BrowserViewRenderer::FallbackTickFired() {
686   TRACE_EVENT1("android_webview",
687                "BrowserViewRenderer::FallbackTickFired",
688                "compositor_needs_continuous_invalidate_",
689                compositor_needs_continuous_invalidate_);
690
691   // This should only be called if OnDraw or DrawGL did not come in time, which
692   // means block_invalidates_ must still be true.
693   DCHECK(block_invalidates_);
694   if (compositor_needs_continuous_invalidate_ && has_compositor_)
695     ForceFakeCompositeSW();
696 }
697
698 void BrowserViewRenderer::ForceFakeCompositeSW() {
699   DCHECK(has_compositor_);
700   SkBitmap bitmap;
701   bitmap.allocN32Pixels(1, 1);
702   bitmap.eraseColor(0);
703   SkCanvas canvas(bitmap);
704   CompositeSW(&canvas);
705 }
706
707 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
708   DCHECK(has_compositor_);
709   bool result = shared_renderer_state_->GetCompositor()->
710       DemandDrawSw(canvas);
711   DidComposite(false);
712   return result;
713 }
714
715 void BrowserViewRenderer::DidComposite(bool force_invalidate) {
716   fallback_tick_.Cancel();
717   block_invalidates_ = false;
718   EnsureContinuousInvalidation(force_invalidate);
719 }
720
721 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
722   std::string str;
723   base::StringAppendF(&str, "is_paused: %d ", is_paused_);
724   base::StringAppendF(&str, "view_visible: %d ", view_visible_);
725   base::StringAppendF(&str, "window_visible: %d ", window_visible_);
726   base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
727   base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
728   base::StringAppendF(&str,
729                       "compositor_needs_continuous_invalidate: %d ",
730                       compositor_needs_continuous_invalidate_);
731   base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
732   base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
733   base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
734   base::StringAppendF(&str,
735                       "global visible rect: %s ",
736                       draw_gl_input_.global_visible_rect.ToString().c_str());
737   base::StringAppendF(
738       &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
739   base::StringAppendF(&str,
740                       "overscroll_rounding_error_: %s ",
741                       overscroll_rounding_error_.ToString().c_str());
742   base::StringAppendF(
743       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
744   base::StringAppendF(&str, "clear_view: %d ", clear_view_);
745   if (draw_info) {
746     base::StringAppendF(&str,
747                         "clip left top right bottom: [%d %d %d %d] ",
748                         draw_info->clip_left,
749                         draw_info->clip_top,
750                         draw_info->clip_right,
751                         draw_info->clip_bottom);
752     base::StringAppendF(&str,
753                         "surface width height: [%d %d] ",
754                         draw_info->width,
755                         draw_info->height);
756     base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
757   }
758   return str;
759 }
760
761 }  // namespace android_webview