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