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