- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / browser / in_process_view_renderer.cc
1 // Copyright 2013 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/in_process_view_renderer.h"
6
7 #include <android/bitmap.h>
8
9 #include "android_webview/browser/aw_gl_surface.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/common/aw_switches.h"
12 #include "android_webview/public/browser/draw_gl.h"
13 #include "android_webview/public/browser/draw_sw.h"
14 #include "base/android/jni_android.h"
15 #include "base/auto_reset.h"
16 #include "base/command_line.h"
17 #include "base/debug/trace_event.h"
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/stringprintf.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/common/content_switches.h"
25 #include "gpu/command_buffer/service/in_process_command_buffer.h"
26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "third_party/skia/include/core/SkBitmapDevice.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h"
31 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
32 #include "ui/gfx/skia_util.h"
33 #include "ui/gfx/transform.h"
34 #include "ui/gfx/vector2d_conversions.h"
35 #include "ui/gfx/vector2d_f.h"
36
37 using base::android::AttachCurrentThread;
38 using base::android::JavaRef;
39 using base::android::ScopedJavaLocalRef;
40 using content::BrowserThread;
41
42 namespace android_webview {
43
44 namespace {
45
46
47 const void* kUserDataKey = &kUserDataKey;
48
49 class UserData : public content::WebContents::Data {
50  public:
51   UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
52   virtual ~UserData() {
53     instance_->WebContentsGone();
54   }
55
56   static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
57     if (!contents)
58       return NULL;
59     UserData* data = reinterpret_cast<UserData*>(
60         contents->GetUserData(kUserDataKey));
61     return data ? data->instance_ : NULL;
62   }
63
64  private:
65   InProcessViewRenderer* instance_;
66 };
67
68 bool RasterizeIntoBitmap(JNIEnv* env,
69                          const JavaRef<jobject>& jbitmap,
70                          int scroll_x,
71                          int scroll_y,
72                          const InProcessViewRenderer::RenderMethod& renderer) {
73   DCHECK(jbitmap.obj());
74
75   AndroidBitmapInfo bitmap_info;
76   if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
77     LOG(ERROR) << "Error getting java bitmap info.";
78     return false;
79   }
80
81   void* pixels = NULL;
82   if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
83     LOG(ERROR) << "Error locking java bitmap pixels.";
84     return false;
85   }
86
87   bool succeeded;
88   {
89     SkBitmap bitmap;
90     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
91                      bitmap_info.width,
92                      bitmap_info.height,
93                      bitmap_info.stride);
94     bitmap.setPixels(pixels);
95
96     SkBitmapDevice device(bitmap);
97     SkCanvas canvas(&device);
98     canvas.translate(-scroll_x, -scroll_y);
99     succeeded = renderer.Run(&canvas);
100   }
101
102   if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
103     LOG(ERROR) << "Error unlocking java bitmap pixels.";
104     return false;
105   }
106
107   return succeeded;
108 }
109
110 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
111   canvas->drawPicture(*picture);
112   return true;
113 }
114
115 class ScopedPixelAccess {
116  public:
117   ScopedPixelAccess(JNIEnv* env, jobject java_canvas) {
118     AwDrawSWFunctionTable* sw_functions =
119         BrowserViewRenderer::GetAwDrawSWFunctionTable();
120     pixels_ = sw_functions ?
121       sw_functions->access_pixels(env, java_canvas) : NULL;
122   }
123   ~ScopedPixelAccess() {
124     if (pixels_)
125       BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_);
126   }
127   AwPixelInfo* pixels() { return pixels_; }
128
129  private:
130   AwPixelInfo* pixels_;
131
132   DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
133 };
134
135 bool HardwareEnabled() {
136   static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
137       switches::kDisableWebViewGLMode);
138   return g_hw_enabled;
139 }
140
141 // Provides software rendering functions from the Android glue layer.
142 // Allows preventing extra copies of data when rendering.
143 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
144
145 const int64 kFallbackTickTimeoutInMilliseconds = 20;
146
147
148 // Used to calculate memory and resource allocation. Determined experimentally.
149 size_t g_memory_multiplier = 10;
150 size_t g_num_gralloc_limit = 150;
151 const size_t kBytesPerPixel = 4;
152 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
153
154 class ScopedAllowGL {
155  public:
156   ScopedAllowGL();
157   ~ScopedAllowGL();
158
159   static bool IsAllowed() {
160     return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
161   }
162
163  private:
164   static bool allow_gl;
165
166   DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
167 };
168
169 ScopedAllowGL::ScopedAllowGL() {
170   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
171   DCHECK(!allow_gl);
172   allow_gl = true;
173 }
174
175 ScopedAllowGL::~ScopedAllowGL() {
176   allow_gl = false;
177 }
178
179 bool ScopedAllowGL::allow_gl = false;
180
181 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
182
183 void RequestProcessGLOnUIThread() {
184   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
185     BrowserThread::PostTask(
186         BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
187     return;
188   }
189
190   InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
191       g_view_renderer_manager.Get().GetMostRecentlyDrawn());
192   if (!renderer || !renderer->RequestProcessGL()) {
193     LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
194                << !!renderer;
195   }
196 }
197
198 }  // namespace
199
200 // Called from different threads!
201 static void ScheduleGpuWork() {
202   if (ScopedAllowGL::IsAllowed()) {
203     gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
204   } else {
205     RequestProcessGLOnUIThread();
206   }
207 }
208
209 // static
210 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
211     AwDrawSWFunctionTable* table) {
212   g_sw_draw_functions = table;
213   gpu::InProcessCommandBuffer::SetScheduleCallback(
214       base::Bind(&ScheduleGpuWork));
215 }
216
217 // static
218 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
219   return g_sw_draw_functions;
220 }
221
222 InProcessViewRenderer::InProcessViewRenderer(
223     BrowserViewRenderer::Client* client,
224     JavaHelper* java_helper,
225     content::WebContents* web_contents)
226     : client_(client),
227       java_helper_(java_helper),
228       web_contents_(web_contents),
229       compositor_(NULL),
230       is_paused_(false),
231       view_visible_(false),
232       window_visible_(false),
233       attached_to_window_(false),
234       dip_scale_(0.0),
235       page_scale_factor_(1.0),
236       on_new_picture_enable_(false),
237       compositor_needs_continuous_invalidate_(false),
238       block_invalidates_(false),
239       width_(0),
240       height_(0),
241       hardware_initialized_(false),
242       hardware_failed_(false),
243       last_egl_context_(NULL),
244       manager_key_(g_view_renderer_manager.Get().NullKey()) {
245   CHECK(web_contents_);
246   web_contents_->SetUserData(kUserDataKey, new UserData(this));
247   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
248
249   // Currently the logic in this class relies on |compositor_| remaining NULL
250   // until the DidInitializeCompositor() call, hence it is not set here.
251 }
252
253 InProcessViewRenderer::~InProcessViewRenderer() {
254   CHECK(web_contents_);
255   content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
256   web_contents_->SetUserData(kUserDataKey, NULL);
257   NoLongerExpectsDrawGL();
258   DCHECK(web_contents_ == NULL);  // WebContentsGone should have been called.
259 }
260
261 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
262   GLViewRendererManager& mru = g_view_renderer_manager.Get();
263   if (manager_key_ != mru.NullKey()) {
264     mru.NoLongerExpectsDrawGL(manager_key_);
265     manager_key_ = mru.NullKey();
266   }
267 }
268
269 // static
270 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
271     content::WebContents* contents) {
272   return UserData::GetInstance(contents);
273 }
274
275 void InProcessViewRenderer::WebContentsGone() {
276   web_contents_ = NULL;
277   compositor_ = NULL;
278 }
279
280 // static
281 void InProcessViewRenderer::CalculateTileMemoryPolicy() {
282   CommandLine* cl = CommandLine::ForCurrentProcess();
283   if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
284     std::string string_value =
285         cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
286     int int_value = 0;
287     if (base::StringToInt(string_value, &int_value) &&
288         int_value >= 2 && int_value <= 50) {
289       g_memory_multiplier = int_value;
290     }
291   }
292
293   if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) {
294     std::string string_value =
295         cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview);
296     int int_value = 0;
297     if (base::StringToInt(string_value, &int_value) &&
298         int_value >= 50 && int_value <= 500) {
299       g_num_gralloc_limit = int_value;
300     }
301   }
302
303   const char kDefaultTileSize[] = "384";
304   if (!cl->HasSwitch(switches::kDefaultTileWidth))
305     cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
306
307   if (!cl->HasSwitch(switches::kDefaultTileHeight))
308     cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
309 }
310
311 bool InProcessViewRenderer::RequestProcessGL() {
312   return client_->RequestDrawGL(NULL);
313 }
314
315 void InProcessViewRenderer::TrimMemory(int level) {
316   // Constants from Android ComponentCallbacks2.
317   enum {
318     TRIM_MEMORY_RUNNING_LOW = 10,
319     TRIM_MEMORY_UI_HIDDEN = 20,
320     TRIM_MEMORY_BACKGROUND = 40,
321   };
322
323   // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
324   // it does not indicate memory pressure, but merely that the app is
325   // backgrounded.
326   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
327     return;
328
329   // Nothing to drop.
330   if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
331     return;
332
333   // Do not release resources on view we expect to get DrawGL soon.
334   if (level < TRIM_MEMORY_BACKGROUND) {
335     client_->UpdateGlobalVisibleRect();
336     if (view_visible_ && window_visible_ &&
337         !cached_global_visible_rect_.IsEmpty()) {
338       return;
339     }
340   }
341
342   if (!eglGetCurrentContext()) {
343     NOTREACHED();
344     return;
345   }
346
347   // Just set the memory limit to 0 and drop all tiles. This will be reset to
348   // normal levels in the next DrawGL call.
349   content::SynchronousCompositorMemoryPolicy policy;
350   policy.bytes_limit = 0;
351   policy.num_resources_limit = 0;
352   if (memory_policy_ == policy)
353     return;
354
355   TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
356   ScopedAppGLStateRestore state_restore(
357       ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
358   gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
359   ScopedAllowGL allow_gl;
360
361   SetMemoryPolicy(policy);
362   ForceFakeCompositeSW();
363 }
364
365 void InProcessViewRenderer::SetMemoryPolicy(
366     content::SynchronousCompositorMemoryPolicy& new_policy) {
367   if (memory_policy_ == new_policy)
368     return;
369
370   memory_policy_ = new_policy;
371   compositor_->SetMemoryPolicy(memory_policy_);
372 }
373
374 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
375   client_->UpdateGlobalVisibleRect();
376 }
377
378 bool InProcessViewRenderer::OnDraw(jobject java_canvas,
379                                    bool is_hardware_canvas,
380                                    const gfx::Vector2d& scroll,
381                                    const gfx::Rect& clip) {
382   scroll_at_start_of_frame_  = scroll;
383   if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
384     // We should be performing a hardware draw here. If we don't have the
385     // comositor yet or if RequestDrawGL fails, it means we failed this draw and
386     // thus return false here to clear to background color for this draw.
387     return compositor_ && client_->RequestDrawGL(java_canvas);
388   }
389   // Perform a software draw
390   return DrawSWInternal(java_canvas, clip);
391 }
392
393 bool InProcessViewRenderer::InitializeHwDraw() {
394   TRACE_EVENT0("android_webview", "InitializeHwDraw");
395   DCHECK(!gl_surface_);
396   gl_surface_  = new AwGLSurface;
397   hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
398   hardware_initialized_ = true;
399
400   if (hardware_failed_)
401     gl_surface_ = NULL;
402
403   return !hardware_failed_;
404 }
405
406 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
407   TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
408
409   manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
410
411   // We need to watch if the current Android context has changed and enforce
412   // a clean-up in the compositor.
413   EGLContext current_context = eglGetCurrentContext();
414   if (!current_context) {
415     TRACE_EVENT_INSTANT0(
416         "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
417     return;
418   }
419
420   ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
421   gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
422   ScopedAllowGL allow_gl;
423
424   if (!attached_to_window_) {
425     TRACE_EVENT_INSTANT0(
426         "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
427     return;
428   }
429
430   if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
431     TRACE_EVENT_INSTANT0(
432         "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
433     return;
434   }
435
436   if (compositor_ && !hardware_initialized_) {
437     if (InitializeHwDraw()) {
438       last_egl_context_ = current_context;
439     } else {
440       TRACE_EVENT_INSTANT0(
441           "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
442       LOG(ERROR) << "WebView hardware initialization failed";
443       return;
444     }
445   }
446
447   UpdateCachedGlobalVisibleRect();
448   if (cached_global_visible_rect_.IsEmpty()) {
449     TRACE_EVENT_INSTANT0("android_webview",
450                          "EarlyOut_EmptyVisibleRect",
451                          TRACE_EVENT_SCOPE_THREAD);
452     return;
453   }
454
455   if (last_egl_context_ != current_context) {
456     // TODO(boliu): Handle context lost
457     TRACE_EVENT_INSTANT0(
458         "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
459   }
460
461   if (!compositor_) {
462     TRACE_EVENT_INSTANT0(
463         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
464     return;
465   }
466
467   // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
468   // well just to be safe.
469   fallback_tick_.Cancel();
470
471   // Update memory budget. This will no-op in compositor if the policy has not
472   // changed since last draw.
473   content::SynchronousCompositorMemoryPolicy policy;
474   policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
475                        cached_global_visible_rect_.width() *
476                        cached_global_visible_rect_.height();
477   // Round up to a multiple of kMemoryAllocationStep.
478   policy.bytes_limit =
479       (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
480   policy.num_resources_limit = g_num_gralloc_limit;
481   SetMemoryPolicy(policy);
482
483   DCHECK(gl_surface_);
484   gl_surface_->SetBackingFrameBufferObject(
485       state_restore.framebuffer_binding_ext());
486
487   gfx::Transform transform;
488   transform.matrix().setColMajorf(draw_info->transform);
489   transform.Translate(scroll_at_start_of_frame_.x(),
490                       scroll_at_start_of_frame_.y());
491   gfx::Rect clip_rect(draw_info->clip_left,
492                       draw_info->clip_top,
493                       draw_info->clip_right - draw_info->clip_left,
494                       draw_info->clip_bottom - draw_info->clip_top);
495
496   // Assume we always draw the full visible rect if we are drawing into a layer.
497   bool drew_full_visible_rect = true;
498
499   gfx::Rect viewport_rect;
500   if (!draw_info->is_layer) {
501     viewport_rect = cached_global_visible_rect_;
502     clip_rect.Intersect(viewport_rect);
503     drew_full_visible_rect = clip_rect.Contains(viewport_rect);
504   } else {
505     viewport_rect = clip_rect;
506   }
507
508   block_invalidates_ = true;
509   // TODO(joth): Check return value.
510   compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
511                             transform,
512                             viewport_rect,
513                             clip_rect,
514                             state_restore.stencil_enabled());
515   block_invalidates_ = false;
516   gl_surface_->ResetBackingFrameBufferObject();
517
518   EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
519 }
520
521 void InProcessViewRenderer::SetGlobalVisibleRect(
522     const gfx::Rect& visible_rect) {
523   cached_global_visible_rect_ = visible_rect;
524 }
525
526 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
527                                            const gfx::Rect& clip) {
528   if (clip.IsEmpty()) {
529     TRACE_EVENT_INSTANT0(
530         "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
531     return true;
532   }
533
534   if (!compositor_) {
535     TRACE_EVENT_INSTANT0(
536         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
537     return false;
538   }
539
540   return RenderViaAuxilaryBitmapIfNeeded(
541       java_canvas,
542       java_helper_,
543       scroll_at_start_of_frame_,
544       clip,
545       base::Bind(&InProcessViewRenderer::CompositeSW,
546                  base::Unretained(this)),
547       web_contents_);
548 }
549
550 // static
551 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
552       jobject java_canvas,
553       BrowserViewRenderer::JavaHelper* java_helper,
554       const gfx::Vector2d& scroll_correction,
555       const gfx::Rect& clip,
556       InProcessViewRenderer::RenderMethod render_source,
557       void* owner_key) {
558   TRACE_EVENT0("android_webview",
559                "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
560
561   JNIEnv* env = AttachCurrentThread();
562   ScopedPixelAccess auto_release_pixels(env, java_canvas);
563   AwPixelInfo* pixels = auto_release_pixels.pixels();
564   if (pixels && pixels->state) {
565     skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
566         SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
567
568     // Workarounds for http://crbug.com/271096: SW draw only supports
569     // translate & scale transforms, and a simple rectangular clip.
570     if (canvas && (!canvas->getTotalClip().isRect() ||
571           (canvas->getTotalMatrix().getType() &
572            ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
573       canvas.clear();
574     }
575     if (canvas) {
576       canvas->translate(scroll_correction.x(), scroll_correction.y());
577       return render_source.Run(canvas.get());
578     }
579   }
580
581   // Render into an auxiliary bitmap if pixel info is not available.
582   ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
583   TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
584   ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
585       env, clip.width(), clip.height(), jcanvas, owner_key));
586   if (!jbitmap.obj()) {
587     TRACE_EVENT_INSTANT0("android_webview",
588                          "EarlyOut_BitmapAllocFail",
589                          TRACE_EVENT_SCOPE_THREAD);
590     return false;
591   }
592
593   if (!RasterizeIntoBitmap(env, jbitmap,
594                            clip.x() - scroll_correction.x(),
595                            clip.y() - scroll_correction.y(),
596                            render_source)) {
597     TRACE_EVENT_INSTANT0("android_webview",
598                          "EarlyOut_RasterizeFail",
599                          TRACE_EVENT_SCOPE_THREAD);
600     return false;
601   }
602
603   java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
604                                     clip.x(), clip.y());
605   return true;
606 }
607
608 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
609                                                               int height) {
610   TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
611
612   // Return empty Picture objects for empty SkPictures.
613   skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
614   if (width <= 0 || height <= 0) {
615     return picture;
616   }
617
618   // Reset scroll back to the origin, will go back to the old
619   // value when scroll_reset is out of scope.
620   base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
621                                                gfx::Vector2d());
622
623   SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
624   if (compositor_)
625     CompositeSW(rec_canvas);
626   picture->endRecording();
627   return picture;
628 }
629
630 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
631   on_new_picture_enable_ = enabled;
632   EnsureContinuousInvalidation(NULL, false);
633 }
634
635 void InProcessViewRenderer::SetIsPaused(bool paused) {
636   TRACE_EVENT_INSTANT1("android_webview",
637                        "InProcessViewRenderer::SetIsPaused",
638                        TRACE_EVENT_SCOPE_THREAD,
639                        "paused",
640                        paused);
641   is_paused_ = paused;
642   EnsureContinuousInvalidation(NULL, false);
643 }
644
645 void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
646   TRACE_EVENT_INSTANT1("android_webview",
647                        "InProcessViewRenderer::SetViewVisibility",
648                        TRACE_EVENT_SCOPE_THREAD,
649                        "view_visible",
650                        view_visible);
651   view_visible_ = view_visible;
652 }
653
654 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
655   TRACE_EVENT_INSTANT1("android_webview",
656                        "InProcessViewRenderer::SetWindowVisibility",
657                        TRACE_EVENT_SCOPE_THREAD,
658                        "window_visible",
659                        window_visible);
660   window_visible_ = window_visible;
661   EnsureContinuousInvalidation(NULL, false);
662 }
663
664 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
665   TRACE_EVENT_INSTANT2("android_webview",
666                        "InProcessViewRenderer::OnSizeChanged",
667                        TRACE_EVENT_SCOPE_THREAD,
668                        "width",
669                        width,
670                        "height",
671                        height);
672   width_ = width;
673   height_ = height;
674 }
675
676 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
677   TRACE_EVENT2("android_webview",
678                "InProcessViewRenderer::OnAttachedToWindow",
679                "width",
680                width,
681                "height",
682                height);
683   attached_to_window_ = true;
684   width_ = width;
685   height_ = height;
686 }
687
688 void InProcessViewRenderer::OnDetachedFromWindow() {
689   TRACE_EVENT0("android_webview",
690                "InProcessViewRenderer::OnDetachedFromWindow");
691
692   NoLongerExpectsDrawGL();
693   if (hardware_initialized_) {
694     DCHECK(compositor_);
695
696     ScopedAppGLStateRestore state_restore(
697         ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
698     gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
699     ScopedAllowGL allow_gl;
700     compositor_->ReleaseHwDraw();
701     hardware_initialized_ = false;
702   }
703
704   gl_surface_ = NULL;
705   attached_to_window_ = false;
706 }
707
708 bool InProcessViewRenderer::IsAttachedToWindow() {
709   return attached_to_window_;
710 }
711
712 bool InProcessViewRenderer::IsVisible() {
713   // Ignore |window_visible_| if |attached_to_window_| is false.
714   return view_visible_ && (!attached_to_window_ || window_visible_);
715 }
716
717 gfx::Rect InProcessViewRenderer::GetScreenRect() {
718   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
719 }
720
721 void InProcessViewRenderer::DidInitializeCompositor(
722     content::SynchronousCompositor* compositor) {
723   TRACE_EVENT0("android_webview",
724                "InProcessViewRenderer::DidInitializeCompositor");
725   DCHECK(compositor && compositor_ == NULL);
726   compositor_ = compositor;
727   hardware_initialized_ = false;
728   hardware_failed_ = false;
729 }
730
731 void InProcessViewRenderer::DidDestroyCompositor(
732     content::SynchronousCompositor* compositor) {
733   TRACE_EVENT0("android_webview",
734                "InProcessViewRenderer::DidDestroyCompositor");
735   DCHECK(compositor_ == compositor);
736
737   // This can fail if Apps call destroy while the webview is still attached
738   // to the view tree. This is an illegal operation that will lead to leaks.
739   // Log for now. Consider a proper fix if this becomes a problem.
740   LOG_IF(ERROR, hardware_initialized_)
741       << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
742   compositor_ = NULL;
743 }
744
745 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
746   if (compositor_needs_continuous_invalidate_ == invalidate)
747     return;
748
749   TRACE_EVENT_INSTANT1("android_webview",
750                        "InProcessViewRenderer::SetContinuousInvalidate",
751                        TRACE_EVENT_SCOPE_THREAD,
752                        "invalidate",
753                        invalidate);
754   compositor_needs_continuous_invalidate_ = invalidate;
755   EnsureContinuousInvalidation(NULL, false);
756 }
757
758 void InProcessViewRenderer::SetDipScale(float dip_scale) {
759   dip_scale_ = dip_scale;
760   CHECK(dip_scale_ > 0);
761 }
762
763 gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const {
764   DCHECK_GT(dip_scale_, 0);
765   return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
766       max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
767 }
768
769 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
770   gfx::Vector2d max_offset = max_scroll_offset();
771   gfx::Vector2dF scroll_offset_dip;
772   // To preserve the invariant that scrolling to the maximum physical pixel
773   // value also scrolls to the maximum dip pixel value we transform the physical
774   // offset into the dip offset by using a proportion (instead of dividing by
775   // dip_scale * page_scale_factor).
776   if (max_offset.x()) {
777     scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
778                             max_offset.x());
779   }
780   if (max_offset.y()) {
781     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
782                             max_offset.y());
783   }
784
785   DCHECK_LE(0, scroll_offset_dip.x());
786   DCHECK_LE(0, scroll_offset_dip.y());
787   DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
788   DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
789
790   if (scroll_offset_dip_ == scroll_offset_dip)
791     return;
792
793   scroll_offset_dip_ = scroll_offset_dip;
794
795   if (compositor_)
796     compositor_->DidChangeRootLayerScrollOffset();
797 }
798
799 void InProcessViewRenderer::DidUpdateContent() {
800   if (on_new_picture_enable_)
801     client_->OnNewPicture();
802 }
803
804 void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
805     gfx::Vector2dF new_value_dip) {
806   DCHECK_GT(dip_scale_, 0);
807
808   max_scroll_offset_dip_ = new_value_dip;
809   DCHECK_LE(0, max_scroll_offset_dip_.x());
810   DCHECK_LE(0, max_scroll_offset_dip_.y());
811
812   client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
813 }
814
815 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
816     gfx::Vector2dF scroll_offset_dip) {
817   // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
818   // DrawGl when http://crbug.com/249972 is fixed.
819   if (scroll_offset_dip_ == scroll_offset_dip)
820     return;
821
822   scroll_offset_dip_ = scroll_offset_dip;
823
824   gfx::Vector2d max_offset = max_scroll_offset();
825   gfx::Vector2d scroll_offset;
826   // For an explanation as to why this is done this way see the comment in
827   // InProcessViewRenderer::ScrollTo.
828   if (max_scroll_offset_dip_.x()) {
829     scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
830                         max_scroll_offset_dip_.x());
831   }
832
833   if (max_scroll_offset_dip_.y()) {
834     scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
835                         max_scroll_offset_dip_.y());
836   }
837
838   DCHECK(0 <= scroll_offset.x());
839   DCHECK(0 <= scroll_offset.y());
840   DCHECK(scroll_offset.x() <= max_offset.x());
841   DCHECK(scroll_offset.y() <= max_offset.y());
842
843   client_->ScrollContainerViewTo(scroll_offset);
844 }
845
846 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
847   return scroll_offset_dip_;
848 }
849
850 bool InProcessViewRenderer::IsExternalFlingActive() const {
851   return client_->IsFlingActive();
852 }
853
854 void InProcessViewRenderer::SetRootLayerPageScaleFactor(
855     float page_scale_factor) {
856   page_scale_factor_ = page_scale_factor;
857   DCHECK_GT(page_scale_factor_, 0);
858   client_->SetPageScaleFactor(page_scale_factor);
859 }
860
861 void InProcessViewRenderer::SetRootLayerScrollableSize(
862     gfx::SizeF scrollable_size) {
863   client_->SetContentsSize(scrollable_size);
864 }
865
866 void InProcessViewRenderer::DidOverscroll(
867     gfx::Vector2dF accumulated_overscroll,
868     gfx::Vector2dF latest_overscroll_delta,
869     gfx::Vector2dF current_fling_velocity) {
870   DCHECK(current_fling_velocity.IsZero());
871   const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
872   if (accumulated_overscroll == latest_overscroll_delta)
873     overscroll_rounding_error_ = gfx::Vector2dF();
874   gfx::Vector2dF scaled_overscroll_delta =
875       gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
876   gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
877       scaled_overscroll_delta + overscroll_rounding_error_);
878   overscroll_rounding_error_ =
879       scaled_overscroll_delta - rounded_overscroll_delta;
880   client_->DidOverscroll(rounded_overscroll_delta);
881 }
882
883 void InProcessViewRenderer::EnsureContinuousInvalidation(
884     AwDrawGLInfo* draw_info,
885     bool invalidate_ignore_compositor) {
886   // This method should be called again when any of these conditions change.
887   bool need_invalidate =
888       compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
889   bool throttle = (is_paused_ && !on_new_picture_enable_) ||
890                   (attached_to_window_ && !window_visible_);
891   if (!need_invalidate || block_invalidates_ || throttle)
892     return;
893
894   if (draw_info) {
895     draw_info->dirty_left = cached_global_visible_rect_.x();
896     draw_info->dirty_top = cached_global_visible_rect_.y();
897     draw_info->dirty_right = cached_global_visible_rect_.right();
898     draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
899     draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
900   } else {
901     client_->PostInvalidate();
902   }
903
904   block_invalidates_ = compositor_needs_continuous_invalidate_;
905
906   // Unretained here is safe because the callback is cancelled when
907   // |fallback_tick_| is destroyed.
908   fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
909                                   base::Unretained(this)));
910
911   // No need to reschedule fallback tick if compositor does not need to be
912   // ticked. This can happen if this is reached because
913   // invalidate_ignore_compositor is true.
914   if (compositor_needs_continuous_invalidate_) {
915     BrowserThread::PostDelayedTask(
916         BrowserThread::UI,
917         FROM_HERE,
918         fallback_tick_.callback(),
919         base::TimeDelta::FromMilliseconds(
920             kFallbackTickTimeoutInMilliseconds));
921   }
922 }
923
924 void InProcessViewRenderer::FallbackTickFired() {
925   TRACE_EVENT1("android_webview",
926                "InProcessViewRenderer::FallbackTickFired",
927                "compositor_needs_continuous_invalidate_",
928                compositor_needs_continuous_invalidate_);
929
930   // This should only be called if OnDraw or DrawGL did not come in time, which
931   // means block_invalidates_ must still be true.
932   DCHECK(block_invalidates_);
933   if (compositor_needs_continuous_invalidate_ && compositor_)
934     ForceFakeCompositeSW();
935 }
936
937 void InProcessViewRenderer::ForceFakeCompositeSW() {
938   DCHECK(compositor_);
939   SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
940   SkCanvas canvas(&device);
941   CompositeSW(&canvas);
942 }
943
944 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
945   DCHECK(compositor_);
946
947   fallback_tick_.Cancel();
948   block_invalidates_ = true;
949   bool result = compositor_->DemandDrawSw(canvas);
950   block_invalidates_ = false;
951   EnsureContinuousInvalidation(NULL, false);
952   return result;
953 }
954
955 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
956   std::string str;
957   base::StringAppendF(&str, "is_paused: %d ", is_paused_);
958   base::StringAppendF(&str, "view_visible: %d ", view_visible_);
959   base::StringAppendF(&str, "window_visible: %d ", window_visible_);
960   base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
961   base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
962   base::StringAppendF(&str,
963                       "compositor_needs_continuous_invalidate: %d ",
964                       compositor_needs_continuous_invalidate_);
965   base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
966   base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
967   base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
968   base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
969   base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
970   base::StringAppendF(&str,
971                       "global visible rect: %s ",
972                       cached_global_visible_rect_.ToString().c_str());
973   base::StringAppendF(&str,
974                       "scroll_at_start_of_frame: %s ",
975                       scroll_at_start_of_frame_.ToString().c_str());
976   base::StringAppendF(
977       &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
978   base::StringAppendF(&str,
979                       "overscroll_rounding_error_: %s ",
980                       overscroll_rounding_error_.ToString().c_str());
981   base::StringAppendF(
982       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
983   if (draw_info) {
984     base::StringAppendF(&str,
985                         "clip left top right bottom: [%d %d %d %d] ",
986                         draw_info->clip_left,
987                         draw_info->clip_top,
988                         draw_info->clip_right,
989                         draw_info->clip_bottom);
990     base::StringAppendF(&str,
991                         "surface width height: [%d %d] ",
992                         draw_info->width,
993                         draw_info->height);
994     base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
995   }
996   return str;
997 }
998
999 }  // namespace android_webview