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