Chromium Code Reviews| Index: android_webview/native/aw_contents.cc |
| diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc |
| index a44fb06c5c6945cbc8b05ac3e8faea6b47783fce..054e8356d5376a238012d3e9adbcec4fd1979d63 100644 |
| --- a/android_webview/native/aw_contents.cc |
| +++ b/android_webview/native/aw_contents.cc |
| @@ -4,6 +4,7 @@ |
| #include "android_webview/native/aw_contents.h" |
| +#include <android/bitmap.h> |
| #include <sys/system_properties.h> |
| #include "android_webview/browser/aw_browser_main_parts.h" |
| @@ -37,11 +38,10 @@ |
| #include "content/public/common/ssl_status.h" |
| #include "jni/AwContents_jni.h" |
| #include "net/base/x509_certificate.h" |
| -#include "skia/ext/refptr.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkDevice.h" |
| -#include "third_party/skia/include/core/SkPicture.h" |
| +#include "third_party/skia/include/core/SkGraphics.h" |
| #include "ui/gfx/transform.h" |
| #include "ui/gl/gl_bindings.h" |
| @@ -79,6 +79,50 @@ static void DrawGLFunction(int view_context, |
| reinterpret_cast<android_webview::AwContents*>(view_context)->DrawGL( |
| draw_info); |
| } |
| + |
| +typedef base::Callback<bool(SkCanvas*)> RenderMethod; |
| + |
| +static bool RasterizeIntoBitmap(JNIEnv* env, |
| + jobject jbitmap, |
| + int scroll_x, |
| + int scroll_y, |
| + const RenderMethod& renderer) { |
| + DCHECK(jbitmap); |
| + |
| + AndroidBitmapInfo bitmap_info; |
| + if (AndroidBitmap_getInfo(env, jbitmap, &bitmap_info) < 0) { |
| + LOG(WARNING) << "Error getting java bitmap info."; |
| + return false; |
| + } |
| + |
| + void* pixels = NULL; |
| + if (AndroidBitmap_lockPixels(env, jbitmap, &pixels) < 0) { |
| + LOG(WARNING) << "Error locking java bitmap pixels."; |
| + return false; |
| + } |
| + |
| + bool succeeded = false; |
| + { |
| + SkBitmap bitmap; |
| + bitmap.setConfig(SkBitmap::kARGB_8888_Config, |
| + bitmap_info.width, |
| + bitmap_info.height, |
| + bitmap_info.stride); |
| + bitmap.setPixels(pixels); |
| + |
| + SkDevice device(bitmap); |
| + SkCanvas canvas(&device); |
| + canvas.translate(-scroll_x, -scroll_y); |
| + succeeded = renderer.Run(&canvas); |
| + } |
| + |
| + if (AndroidBitmap_unlockPixels(env, jbitmap) < 0) { |
| + LOG(WARNING) << "Error unlocking java bitmap pixels."; |
| + return false; |
| + } |
| + |
| + return succeeded; |
| +} |
| } |
| namespace android_webview { |
| @@ -86,6 +130,7 @@ namespace android_webview { |
| namespace { |
| AwDrawSWFunctionTable* g_draw_sw_functions = NULL; |
| +bool g_is_skia_version_compatible = false; |
| const void* kAwContentsUserDataKey = &kAwContentsUserDataKey; |
| @@ -121,6 +166,7 @@ AwContents::AwContents(JNIEnv* env, |
| view_visible_(false), |
| compositor_visible_(false), |
| is_composite_pending_(false), |
| + on_new_picture_mode_(kOnNewPictureDisabled), |
| last_frame_context_(NULL) { |
| RendererPictureMap::CreateInstance(); |
| android_webview::AwBrowserDependencyFactory* dependency_factory = |
| @@ -378,20 +424,35 @@ void AwContents::DrawGL(AwDrawGLInfo* draw_info) { |
| // --------------------------------------------------------------------------- |
| } |
| -bool AwContents::DrawSW(JNIEnv* env, jobject obj, jobject java_canvas) { |
| - skia::RefPtr<SkPicture> picture = |
| - RendererPictureMap::GetInstance()->GetRendererPicture( |
| - web_contents_->GetRoutingID()); |
| - if (!picture) |
| - return false; |
| +bool AwContents::DrawSW(JNIEnv* env, |
| + jobject obj, |
| + jobject java_canvas, |
| + jint clip_x, |
| + jint clip_y, |
| + jint clip_w, |
| + jint clip_h) { |
| + TRACE_EVENT0("AwContents", "AwContents::DrawSW"); |
| AwPixelInfo* pixels; |
| + |
| + // Render into an auxiliary bitmap if pixel info is not available. |
| if (!g_draw_sw_functions || |
| (pixels = g_draw_sw_functions->access_pixels(env, java_canvas)) == NULL) { |
| - // TODO(joth): Fall back to slow path rendering via temporary bitmap. |
| - return false; |
| + ScopedJavaLocalRef<jobject> jbitmap(Java_AwContents_createBitmap( |
| + env, clip_w, clip_h)); |
| + if (!jbitmap.obj()) |
| + return false; |
| + |
| + if (!RasterizeIntoBitmap(env, jbitmap.obj(), clip_x, clip_y, |
| + base::Bind(&AwContents::RenderSW, base::Unretained(this)))) |
| + return false; |
| + |
| + Java_AwContents_drawBitmapIntoCanvas(env, jbitmap.obj(), java_canvas); |
| + return true; |
| } |
| + // Draw in a SkCanvas built over the pixel information. |
| + bool succeeded = false; |
| { |
| SkBitmap bitmap; |
| bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config), |
| @@ -415,11 +476,11 @@ bool AwContents::DrawSW(JNIEnv* env, jobject obj, jobject java_canvas) { |
| clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height)); |
| } |
| - picture->draw(&canvas); |
| + succeeded = RenderSW(&canvas); |
| } |
| g_draw_sw_functions->release_pixels(pixels); |
| - return true; |
| + return succeeded; |
| } |
| jint AwContents::GetWebContents(JNIEnv* env, jobject obj) { |
| @@ -462,6 +523,11 @@ void AwContents::Destroy(JNIEnv* env, jobject obj) { |
| void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) { |
| g_draw_sw_functions = |
| reinterpret_cast<AwDrawSWFunctionTable*>(function_table); |
| + // TODO(leandrogracia): uncomment once the glue layer implements this method. |
| + //g_is_skia_version_compatible = |
| + // g_draw_sw_functions->is_skia_version_compatible(&SkGraphics::GetVersion); |
| + if (!g_is_skia_version_compatible) |
| + LOG(WARNING) << "Skia native versions are not compatible."; |
|
joth
2013/01/22 00:05:41
LOG_IF(!g_is_skia_version_compatible, WARNING) <<
Leandro Graciá Gil
2013/01/22 02:11:13
Didn't know that one. Done. (Btw, it's LOG_IF(seve
|
| } |
| // static |
| @@ -696,7 +762,13 @@ void AwContents::Invalidate() { |
| if (obj.is_null()) |
| return; |
| - Java_AwContents_invalidate(env, obj.obj()); |
| + if (view_visible_) |
| + Java_AwContents_invalidate(env, obj.obj()); |
| + |
| + // When not in invalidation-only mode onNewPicture will be triggered |
| + // from the OnPictureUpdated callback. |
| + if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly) |
| + Java_AwContents_onNewPicture(env, obj.obj(), NULL); |
| } |
| void AwContents::SetCompositorVisibility(bool visible) { |
| @@ -848,14 +920,104 @@ jint AwContents::ReleasePopupWebContents(JNIEnv* env, jobject obj) { |
| return reinterpret_cast<jint>(pending_contents_.release()); |
| } |
| +ScopedJavaLocalRef<jobject> AwContents::CapturePicture(JNIEnv* env, |
| + jobject obj) { |
| + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); |
| + if (!picture || !g_draw_sw_functions) |
| + return ScopedJavaLocalRef<jobject>(); |
| + |
| + if (g_is_skia_version_compatible) |
| + return ScopedJavaLocalRef<jobject>(env, |
| + g_draw_sw_functions->create_picture(env, picture->clone())); |
| + |
| + // If Skia versions are not compatible, workaround it by rasterizing the |
| + // picture into a bitmap and drawing it into a new Java picture. |
| + ScopedJavaLocalRef<jobject> jbitmap(Java_AwContents_createBitmap( |
| + env, picture->width(), picture->height())); |
| + if (!jbitmap.obj()) |
| + return ScopedJavaLocalRef<jobject>(); |
| + |
| + if (!RasterizeIntoBitmap(env, jbitmap.obj(), 0, 0, |
| + base::Bind(&AwContents::RenderPicture, base::Unretained(this)))) |
| + return ScopedJavaLocalRef<jobject>(); |
| + |
| + return Java_AwContents_recordRasterizedBitmap(env, jbitmap.obj()); |
| +} |
| + |
| +bool AwContents::RenderSW(SkCanvas* canvas) { |
| + // TODO(leandrogracia): once Ubercompositor is ready and we support software |
| + // rendering mode, we should avoid this as much as we can, ideally always. |
| + // This includes finding a proper replacement for onDraw calls in hardware |
| + // mode with software canvases. http://crbug.com/170086. |
| + return RenderPicture(canvas); |
| +} |
| + |
| +bool AwContents::RenderPicture(SkCanvas* canvas) { |
| + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); |
| + if (!picture) |
| + return false; |
| + |
| + picture->draw(canvas); |
| + return true; |
| +} |
| + |
| +void AwContents::EnableOnNewPicture(JNIEnv* env, |
| + jobject obj, |
| + jboolean enabled, |
| + jboolean invalidation_only) { |
| + if (enabled) { |
| + on_new_picture_mode_ = invalidation_only ? kOnNewPictureInvalidationOnly : |
| + kOnNewPictureEnabled; |
| + } else { |
| + on_new_picture_mode_ = kOnNewPictureDisabled; |
| + } |
| + |
| + // If onNewPicture is triggered only on invalidation do not capture |
| + // pictures on every new frame. |
| + if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly) |
| + enabled = false; |
| + |
| + // TODO(leandrogracia): uncomment when sw rendering uses Ubercompositor. |
|
joth
2013/01/22 00:05:41
I'd rather we leave "TODO: uncomment..." for thing
Leandro Graciá Gil
2013/01/22 02:11:13
Done.
|
| + // Until then we need the callback enabled for SW mode invalidation. |
| + // render_view_host_ext_->EnableCapturePictureCallback(enabled); |
| +} |
| + |
| void AwContents::OnPictureUpdated(int process_id, int render_view_id) { |
| CHECK_EQ(web_contents_->GetRenderProcessHost()->GetID(), process_id); |
| if (render_view_id != web_contents_->GetRoutingID()) |
| return; |
| + // TODO(leandrogracia): this can be made unconditional once software rendering |
| + // uses Ubercompositor. Until then this path is required for SW invalidations. |
| + if (on_new_picture_mode_ == kOnNewPictureEnabled) { |
| + JNIEnv* env = AttachCurrentThread(); |
| + ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
| + if (!obj.is_null()) { |
| + ScopedJavaLocalRef<jobject> picture = CapturePicture(env, obj.obj()); |
| + Java_AwContents_onNewPicture(env, obj.obj(), picture.obj()); |
| + } |
| + } |
| + |
| // TODO(leandrogracia): delete when sw rendering uses Ubercompositor. |
| // Invalidation should be provided by the compositor only. |
| Invalidate(); |
| } |
| +skia::RefPtr<SkPicture> AwContents::GetLastCapturedPicture() { |
| + // Use the latest available picture if the listener callback is enabled. |
| + skia::RefPtr<SkPicture> picture; |
| + if (on_new_picture_mode_ == kOnNewPictureEnabled) |
| + picture = RendererPictureMap::GetInstance()->GetRendererPicture( |
| + web_contents_->GetRoutingID()); |
| + |
| + // If not available or not in listener mode get it synchronously. |
| + if (!picture) { |
| + render_view_host_ext_->CapturePictureSync(); |
| + picture = RendererPictureMap::GetInstance()->GetRendererPicture( |
| + web_contents_->GetRoutingID()); |
| + } |
| + |
| + return picture; |
| +} |
| + |
| } // namespace android_webview |