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