Home | History | Annotate | Download | only in native
      1 // Copyright (c) 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/native/java_browser_view_renderer_helper.h"
      6 
      7 #include <android/bitmap.h>
      8 
      9 #include "android_webview/common/aw_switches.h"
     10 #include "android_webview/public/browser/draw_sw.h"
     11 #include "base/debug/trace_event.h"
     12 #include "jni/JavaBrowserViewRendererHelper_jni.h"
     13 #include "third_party/skia/include/core/SkBitmap.h"
     14 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
     15 
     16 using base::android::JavaRef;
     17 using base::android::ScopedJavaLocalRef;
     18 
     19 namespace android_webview {
     20 
     21 namespace {
     22 
     23 // Provides software rendering functions from the Android glue layer.
     24 // Allows preventing extra copies of data when rendering.
     25 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
     26 
     27 class ScopedPixelAccess {
     28  public:
     29   ScopedPixelAccess(JNIEnv* env, jobject java_canvas) : pixels_(NULL) {
     30     if (g_sw_draw_functions && !switches::ForceAuxiliaryBitmap())
     31       pixels_ = g_sw_draw_functions->access_pixels(env, java_canvas);
     32   }
     33 
     34   ~ScopedPixelAccess() {
     35     if (pixels_)
     36       g_sw_draw_functions->release_pixels(pixels_);
     37   }
     38 
     39   AwPixelInfo* pixels() { return pixels_; }
     40 
     41  private:
     42   AwPixelInfo* pixels_;
     43 
     44   DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
     45 };
     46 
     47 }  // namespace
     48 
     49 // static
     50 void JavaBrowserViewRendererHelper::SetAwDrawSWFunctionTable(
     51     AwDrawSWFunctionTable* table) {
     52   g_sw_draw_functions = table;
     53 }
     54 
     55 // static
     56 JavaBrowserViewRendererHelper* JavaBrowserViewRendererHelper::GetInstance() {
     57   static JavaBrowserViewRendererHelper* g_instance =
     58       new JavaBrowserViewRendererHelper;
     59   return g_instance;
     60 }
     61 
     62 // static
     63 BrowserViewRendererJavaHelper* BrowserViewRendererJavaHelper::GetInstance() {
     64   return JavaBrowserViewRendererHelper::GetInstance();
     65 }
     66 
     67 JavaBrowserViewRendererHelper::JavaBrowserViewRendererHelper() {}
     68 
     69 JavaBrowserViewRendererHelper::~JavaBrowserViewRendererHelper() {}
     70 
     71 bool JavaBrowserViewRendererHelper::RenderViaAuxilaryBitmapIfNeeded(
     72     jobject java_canvas,
     73     const gfx::Vector2d& scroll_correction,
     74     const gfx::Size& auxiliary_bitmap_size,
     75     RenderMethod render_source) {
     76   TRACE_EVENT0("android_webview", "RenderViaAuxilaryBitmapIfNeeded");
     77 
     78   JNIEnv* env = base::android::AttachCurrentThread();
     79   ScopedPixelAccess auto_release_pixels(env, java_canvas);
     80   AwPixelInfo* pixels = auto_release_pixels.pixels();
     81   if (pixels && pixels->state) {
     82     skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
     83         SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
     84 
     85     // Workarounds for http://crbug.com/271096: SW draw only supports
     86     // translate & scale transforms, and a simple rectangular clip.
     87     if (canvas && (!canvas->isClipRect() ||
     88                    (canvas->getTotalMatrix().getType() &
     89                     ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
     90       canvas.clear();
     91     }
     92     if (canvas) {
     93       canvas->translate(scroll_correction.x(), scroll_correction.y());
     94       return render_source.Run(canvas.get());
     95     }
     96   }
     97   return RenderViaAuxilaryBitmap(env,
     98                                  java_canvas,
     99                                  scroll_correction,
    100                                  auxiliary_bitmap_size,
    101                                  render_source);
    102 }
    103 
    104 bool JavaBrowserViewRendererHelper::RenderViaAuxilaryBitmap(
    105     JNIEnv* env,
    106     jobject java_canvas,
    107     const gfx::Vector2d& scroll_correction,
    108     const gfx::Size& auxiliary_bitmap_size,
    109     const RenderMethod& render_source) {
    110   // Render into an auxiliary bitmap if pixel info is not available.
    111   ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
    112   TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
    113 
    114   if (auxiliary_bitmap_size.width() <= 0 || auxiliary_bitmap_size.height() <= 0)
    115     return false;
    116 
    117   ScopedJavaLocalRef<jobject> jbitmap(
    118       Java_JavaBrowserViewRendererHelper_createBitmap(
    119           env,
    120           auxiliary_bitmap_size.width(),
    121           auxiliary_bitmap_size.height(),
    122           jcanvas.obj()));
    123   if (!jbitmap.obj())
    124     return false;
    125 
    126   if (!RasterizeIntoBitmap(env,
    127                            jbitmap,
    128                            render_source)) {
    129     return false;
    130   }
    131 
    132   Java_JavaBrowserViewRendererHelper_drawBitmapIntoCanvas(
    133       env,
    134       jbitmap.obj(),
    135       jcanvas.obj(),
    136       scroll_correction.x(),
    137       scroll_correction.y());
    138   return true;
    139 }
    140 
    141 bool RegisterJavaBrowserViewRendererHelper(JNIEnv* env) {
    142   return RegisterNativesImpl(env);
    143 }
    144 
    145 bool JavaBrowserViewRendererHelper::RasterizeIntoBitmap(
    146     JNIEnv* env,
    147     const JavaRef<jobject>& jbitmap,
    148     const JavaBrowserViewRendererHelper::RenderMethod& renderer) {
    149   DCHECK(jbitmap.obj());
    150 
    151   AndroidBitmapInfo bitmap_info;
    152   if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
    153     LOG(ERROR) << "Error getting java bitmap info.";
    154     return false;
    155   }
    156 
    157   void* pixels = NULL;
    158   if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
    159     LOG(ERROR) << "Error locking java bitmap pixels.";
    160     return false;
    161   }
    162 
    163   bool succeeded;
    164   {
    165     SkImageInfo info =
    166         SkImageInfo::MakeN32Premul(bitmap_info.width, bitmap_info.height);
    167     SkBitmap bitmap;
    168     bitmap.installPixels(info, pixels, bitmap_info.stride);
    169 
    170     SkCanvas canvas(bitmap);
    171     succeeded = renderer.Run(&canvas);
    172   }
    173 
    174   if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
    175     LOG(ERROR) << "Error unlocking java bitmap pixels.";
    176     return false;
    177   }
    178 
    179   return succeeded;
    180 }
    181 
    182 }  // namespace android_webview
    183