667aee69a89633a4f6a81d508ea1721e3a4782c0
[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 "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"
29
30 using base::android::AttachCurrentThread;
31 using base::android::JavaRef;
32 using base::android::ScopedJavaLocalRef;
33 using content::BrowserThread;
34 using content::SynchronousCompositorMemoryPolicy;
35
36 namespace android_webview {
37
38 namespace {
39
40 const int64 kFallbackTickTimeoutInMilliseconds = 100;
41
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;
47
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.
53 size_t g_tile_area;
54
55 class TracedValue : public base::debug::ConvertableToTraceFormat {
56  public:
57   explicit TracedValue(base::Value* value) : value_(value) {}
58   static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue(
59       base::Value* value) {
60     return scoped_refptr<base::debug::ConvertableToTraceFormat>(
61         new TracedValue(value));
62   }
63   virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
64     std::string tmp;
65     base::JSONWriter::Write(value_.get(), &tmp);
66     *out += tmp;
67   }
68
69  private:
70   virtual ~TracedValue() {}
71   scoped_ptr<base::Value> value_;
72
73   DISALLOW_COPY_AND_ASSIGN(TracedValue);
74 };
75
76 }  // namespace
77
78 // static
79 void BrowserViewRenderer::CalculateTileMemoryPolicy(bool use_zero_copy) {
80   CommandLine* cl = CommandLine::ForCurrentProcess();
81
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) {
86     base::StringToUint64(
87         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
88             switches::kForceGpuMemAvailableMb),
89         &g_memory_override_in_bytes);
90     g_memory_override_in_bytes *= 1024 * 1024;
91   }
92
93   if (!use_zero_copy) {
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;
97
98     // Also use a high tile limit since there are no file descriptor issues.
99     GlobalTileManager::GetInstance()->SetTileLimit(1000);
100     return;
101   }
102
103   const char kDefaultTileSize[] = "384";
104
105   if (!cl->HasSwitch(switches::kDefaultTileWidth))
106     cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
107
108   if (!cl->HasSwitch(switches::kDefaultTileHeight))
109     cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
110
111   size_t tile_size;
112   base::StringToSizeT(kDefaultTileSize, &tile_size);
113   g_tile_area = tile_size * tile_size;
114 }
115
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)
121     : client_(client),
122       shared_renderer_state_(shared_renderer_state),
123       web_contents_(web_contents),
124       ui_task_runner_(ui_task_runner),
125       compositor_(NULL),
126       is_paused_(false),
127       view_visible_(false),
128       window_visible_(false),
129       attached_to_window_(false),
130       hardware_enabled_(false),
131       dip_scale_(0.0),
132       page_scale_factor_(1.0),
133       on_new_picture_enable_(false),
134       clear_view_(false),
135       compositor_needs_continuous_invalidate_(false),
136       block_invalidates_(false),
137       width_(0),
138       height_(0) {
139   CHECK(web_contents_);
140   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
141
142   // Currently the logic in this class relies on |compositor_| remaining
143   // NULL until the DidInitializeCompositor() call, hence it is not set here.
144 }
145
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.
150 }
151
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.
156   enum {
157     TRIM_MEMORY_RUNNING_LOW = 10,
158     TRIM_MEMORY_UI_HIDDEN = 20,
159     TRIM_MEMORY_BACKGROUND = 40,
160   };
161
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
164   // backgrounded.
165   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
166     return;
167
168   // Do not release resources on view we expect to get DrawGL soon.
169   if (level < TRIM_MEMORY_BACKGROUND && visible)
170     return;
171
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)
176     return;
177
178   TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
179
180   RequestMemoryPolicy(zero_policy);
181   EnforceMemoryPolicyImmediately(zero_policy);
182 }
183
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.
191   policy.bytes_limit =
192       (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
193
194   if (g_memory_override_in_bytes)
195     policy.bytes_limit = static_cast<size_t>(g_memory_override_in_bytes);
196
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;
202   return policy;
203 }
204
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();
210
211   // The following line will call BrowserViewRenderer::SetMemoryPolicy().
212   manager->RequestTiles(new_policy, tile_manager_key_);
213 }
214
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_);
221 }
222
223 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
224     SynchronousCompositorMemoryPolicy new_policy) {
225   compositor_->SetMemoryPolicy(new_policy);
226   ForceFakeCompositeSW();
227 }
228
229 SynchronousCompositorMemoryPolicy BrowserViewRenderer::GetMemoryPolicy() const {
230   return memory_policy_;
231 }
232
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;
239
240   if (clear_view_)
241     return false;
242
243   if (is_hardware_canvas && attached_to_window_ &&
244       !switches::ForceAuxiliaryBitmap()) {
245     return OnDrawHardware(java_canvas);
246   }
247
248   // Perform a software draw
249   return OnDrawSoftware(java_canvas);
250 }
251
252 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
253   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
254   if (!compositor_)
255     return false;
256
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);
263   }
264
265   if (!hardware_enabled_) {
266     hardware_enabled_ = compositor_->InitializeHwDraw();
267     if (hardware_enabled_) {
268       tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
269     }
270   }
271   if (!hardware_enabled_)
272     return false;
273
274   ReturnResourceFromParent();
275   SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy();
276   RequestMemoryPolicy(new_policy);
277   compositor_->SetMemoryPolicy(memory_policy_);
278
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.
284     DidComposite();
285     return client_->RequestDrawGL(java_canvas, false);
286   }
287
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_;
292
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;
299
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;
306   else
307     viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
308
309   scoped_ptr<cc::CompositorFrame> frame =
310       compositor_->DemandDrawHw(surface_size,
311                                 gfx::Transform(),
312                                 viewport,
313                                 clip,
314                                 viewport_rect_for_tile_priority,
315                                 transform_for_tile_priority);
316   if (!frame.get())
317     return false;
318
319   GlobalTileManager::GetInstance()->DidUse(tile_manager_key_);
320
321   frame->AssignTo(&draw_gl_input->frame);
322   shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());
323   DidComposite();
324   return client_->RequestDrawGL(java_canvas, false);
325 }
326
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);
335   }
336 }
337
338 void BrowserViewRenderer::ReturnUnusedResource(scoped_ptr<DrawGLInput> input) {
339   if (!input.get())
340     return;
341
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);
348 }
349
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);
355   }
356 }
357
358 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) {
359   if (!compositor_) {
360     TRACE_EVENT_INSTANT0(
361         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
362     return false;
363   }
364
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
370   // bitmap.
371   return BrowserViewRendererJavaHelper::GetInstance()
372       ->RenderViaAuxilaryBitmapIfNeeded(
373           java_canvas,
374           last_on_draw_scroll_offset_,
375           gfx::Size(width_, height_),
376           base::Bind(&BrowserViewRenderer::CompositeSW,
377                      base::Unretained(this)));
378 }
379
380 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
381                                                             int height) {
382   TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
383
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());
389   }
390
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_,
394                                                gfx::Vector2dF());
395
396   SkPictureRecorder recorder;
397   SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
398   if (compositor_)
399     CompositeSW(rec_canvas);
400   return skia::AdoptRef(recorder.endRecording());
401 }
402
403 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
404   on_new_picture_enable_ = enabled;
405 }
406
407 void BrowserViewRenderer::ClearView() {
408   TRACE_EVENT_INSTANT0("android_webview",
409                        "BrowserViewRenderer::ClearView",
410                        TRACE_EVENT_SCOPE_THREAD);
411   if (clear_view_)
412     return;
413
414   clear_view_ = true;
415   // Always invalidate ignoring the compositor to actually clear the webview.
416   EnsureContinuousInvalidation(true);
417 }
418
419 void BrowserViewRenderer::SetIsPaused(bool paused) {
420   TRACE_EVENT_INSTANT1("android_webview",
421                        "BrowserViewRenderer::SetIsPaused",
422                        TRACE_EVENT_SCOPE_THREAD,
423                        "paused",
424                        paused);
425   is_paused_ = paused;
426   EnsureContinuousInvalidation(false);
427 }
428
429 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
430   TRACE_EVENT_INSTANT1("android_webview",
431                        "BrowserViewRenderer::SetViewVisibility",
432                        TRACE_EVENT_SCOPE_THREAD,
433                        "view_visible",
434                        view_visible);
435   view_visible_ = view_visible;
436 }
437
438 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
439   TRACE_EVENT_INSTANT1("android_webview",
440                        "BrowserViewRenderer::SetWindowVisibility",
441                        TRACE_EVENT_SCOPE_THREAD,
442                        "window_visible",
443                        window_visible);
444   window_visible_ = window_visible;
445   EnsureContinuousInvalidation(false);
446 }
447
448 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
449   TRACE_EVENT_INSTANT2("android_webview",
450                        "BrowserViewRenderer::OnSizeChanged",
451                        TRACE_EVENT_SCOPE_THREAD,
452                        "width",
453                        width,
454                        "height",
455                        height);
456   width_ = width;
457   height_ = height;
458 }
459
460 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
461   TRACE_EVENT2("android_webview",
462                "BrowserViewRenderer::OnAttachedToWindow",
463                "width",
464                width,
465                "height",
466                height);
467   attached_to_window_ = true;
468   width_ = width;
469   height_ = height;
470 }
471
472 void BrowserViewRenderer::OnDetachedFromWindow() {
473   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
474   attached_to_window_ = false;
475   DCHECK(!hardware_enabled_);
476 }
477
478 void BrowserViewRenderer::ReleaseHardware() {
479   DCHECK(hardware_enabled_);
480   ReturnUnusedResource(shared_renderer_state_->PassDrawGLInput());
481   ReturnResourceFromParent();
482   DCHECK(shared_renderer_state_->ReturnedResourcesEmpty());
483
484   compositor_->ReleaseHwDraw();
485   hardware_enabled_ = false;
486
487   SynchronousCompositorMemoryPolicy zero_policy;
488   RequestMemoryPolicy(zero_policy);
489   GlobalTileManager::GetInstance()->Remove(tile_manager_key_);
490 }
491
492 bool BrowserViewRenderer::IsVisible() const {
493   // Ignore |window_visible_| if |attached_to_window_| is false.
494   return view_visible_ && (!attached_to_window_ || window_visible_);
495 }
496
497 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
498   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
499 }
500
501 void BrowserViewRenderer::DidInitializeCompositor(
502     content::SynchronousCompositor* compositor) {
503   TRACE_EVENT0("android_webview",
504                "BrowserViewRenderer::DidInitializeCompositor");
505   DCHECK(compositor);
506   DCHECK(!compositor_);
507   compositor_ = compositor;
508 }
509
510 void BrowserViewRenderer::DidDestroyCompositor(
511     content::SynchronousCompositor* compositor) {
512   TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
513   DCHECK(compositor_);
514   compositor_ = NULL;
515   SynchronousCompositorMemoryPolicy zero_policy;
516   DCHECK(memory_policy_ == zero_policy);
517 }
518
519 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
520   if (compositor_needs_continuous_invalidate_ == invalidate)
521     return;
522
523   TRACE_EVENT_INSTANT1("android_webview",
524                        "BrowserViewRenderer::SetContinuousInvalidate",
525                        TRACE_EVENT_SCOPE_THREAD,
526                        "invalidate",
527                        invalidate);
528   compositor_needs_continuous_invalidate_ = invalidate;
529
530   EnsureContinuousInvalidation(false);
531 }
532
533 void BrowserViewRenderer::SetDipScale(float dip_scale) {
534   dip_scale_ = dip_scale;
535   CHECK_GT(dip_scale_, 0);
536 }
537
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_));
542 }
543
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()) /
553                             max_offset.x());
554   }
555   if (max_offset.y()) {
556     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
557                             max_offset.y());
558   }
559
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());
564
565   if (scroll_offset_dip_ == scroll_offset_dip)
566     return;
567
568   scroll_offset_dip_ = scroll_offset_dip;
569
570   TRACE_EVENT_INSTANT2("android_webview",
571                "BrowserViewRenderer::ScrollTo",
572                TRACE_EVENT_SCOPE_THREAD,
573                "x",
574                scroll_offset_dip.x(),
575                "y",
576                scroll_offset_dip.y());
577
578   if (compositor_)
579     compositor_->DidChangeRootLayerScrollOffset();
580 }
581
582 void BrowserViewRenderer::DidUpdateContent() {
583   TRACE_EVENT_INSTANT0("android_webview",
584                        "BrowserViewRenderer::DidUpdateContent",
585                        TRACE_EVENT_SCOPE_THREAD);
586   clear_view_ = false;
587   if (on_new_picture_enable_)
588     client_->OnNewPicture();
589 }
590
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)
596     return;
597
598   scroll_offset_dip_ = scroll_offset_dip;
599
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());
607   }
608
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());
612   }
613
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());
618
619   client_->ScrollContainerViewTo(scroll_offset);
620 }
621
622 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
623   return scroll_offset_dip_;
624 }
625
626 bool BrowserViewRenderer::IsExternalFlingActive() const {
627   return client_->IsFlingActive();
628 }
629
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(
638       "android_webview",
639       "BrowserViewRenderer::UpdateRootLayerState",
640       TRACE_EVENT_SCOPE_THREAD,
641       "state",
642       TracedValue::FromValue(
643           RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip)
644               .release()));
645
646   DCHECK_GT(dip_scale_, 0);
647
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());
651
652   page_scale_factor_ = page_scale_factor;
653   DCHECK_GT(page_scale_factor_, 0);
654
655   client_->UpdateScrollState(max_scroll_offset(),
656                              scrollable_size_dip,
657                              page_scale_factor,
658                              min_page_scale_factor,
659                              max_page_scale_factor);
660   SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
661 }
662
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);
667
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());
670
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());
673
674   state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
675   state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
676
677   state->SetDouble("page_scale_factor", page_scale_factor_);
678   return state.PassAs<base::Value>();
679 }
680
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);
694 }
695
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_)
701     return;
702
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();
706
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)
716     return;
717
718   block_invalidates_ = compositor_needs_continuous_invalidate_;
719
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();
725
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
728   // true.
729   if (compositor_needs_continuous_invalidate_)
730     ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
731 }
732
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(
739         FROM_HERE,
740         fallback_tick_fired_.callback(),
741         base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
742   } else {
743     // Pretend we just composited to unblock further invalidates.
744     DidComposite();
745   }
746 }
747
748 void BrowserViewRenderer::FallbackTickFired() {
749   TRACE_EVENT1("android_webview",
750                "BrowserViewRenderer::FallbackTickFired",
751                "compositor_needs_continuous_invalidate_",
752                compositor_needs_continuous_invalidate_);
753
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();
759   } else {
760     // Pretend we just composited to unblock further invalidates.
761     DidComposite();
762   }
763 }
764
765 void BrowserViewRenderer::ForceFakeCompositeSW() {
766   DCHECK(compositor_);
767   SkBitmap bitmap;
768   bitmap.allocN32Pixels(1, 1);
769   bitmap.eraseColor(0);
770   SkCanvas canvas(bitmap);
771   CompositeSW(&canvas);
772 }
773
774 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
775   DCHECK(compositor_);
776   ReturnResourceFromParent();
777   bool result = compositor_->DemandDrawSw(canvas);
778   DidComposite();
779   return result;
780 }
781
782 void BrowserViewRenderer::DidComposite() {
783   block_invalidates_ = false;
784   post_fallback_tick_.Cancel();
785   fallback_tick_fired_.Cancel();
786   EnsureContinuousInvalidation(false);
787 }
788
789 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
790   std::string str;
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());
805   base::StringAppendF(
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());
810   base::StringAppendF(
811       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
812   base::StringAppendF(&str, "clear_view: %d ", clear_view_);
813   if (draw_info) {
814     base::StringAppendF(&str,
815                         "clip left top right bottom: [%d %d %d %d] ",
816                         draw_info->clip_left,
817                         draw_info->clip_top,
818                         draw_info->clip_right,
819                         draw_info->clip_bottom);
820     base::StringAppendF(&str,
821                         "surface width height: [%d %d] ",
822                         draw_info->width,
823                         draw_info->height);
824     base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
825   }
826   return str;
827 }
828
829 }  // namespace android_webview