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..6387537b0d3527b57548f55904c43194b741f975 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" |
@@ -86,6 +86,7 @@ namespace android_webview { |
namespace { |
AwDrawSWFunctionTable* g_draw_sw_functions = NULL; |
+bool g_is_skia_version_compatible = false; |
const void* kAwContentsUserDataKey = &kAwContentsUserDataKey; |
@@ -121,6 +122,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 = |
@@ -379,9 +381,11 @@ 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()); |
+ // TODO(leandrogracia): once Ubercompositor is ready and we support software |
palmer
2013/01/15 01:16:19
I'd file a bug and refer to it here.
Leandro Graciá Gil
2013/01/15 18:49:23
Done.
|
+ // 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. |
+ skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); |
if (!picture) |
return false; |
@@ -462,6 +466,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. |
palmer
2013/01/15 01:16:19
Here, too.
Leandro Graciá Gil
2013/01/15 18:49:23
This one is intended to be very shortly-lived, pro
|
+ //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."; |
} |
// static |
@@ -696,7 +705,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 +863,123 @@ 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. |
+ return ScopedJavaLocalRef<jobject>( |
+ Java_AwContents_rasterizeIntoPicture(env, obj, |
+ reinterpret_cast<jint>(picture.get()), |
+ picture->width(), picture->height())); |
+} |
+ |
+// static |
+jboolean RasterizePicture(JNIEnv* env, |
+ jclass clazz, |
+ jobject jbitmap, |
+ jint native_picture) { |
+ DCHECK(jbitmap); |
+ DCHECK(native_picture); |
+ |
+ 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; |
+ } |
+ |
+ { |
+ 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); |
+ SkPicture* picture = reinterpret_cast<SkPicture*>(native_picture); |
+ picture->draw(&canvas); |
+ } |
+ |
+ if (AndroidBitmap_unlockPixels(env, jbitmap) < 0) { |
+ LOG(WARNING) << "Error unlocking java bitmap pixels."; |
+ return false; |
+ } |
+ |
+ 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. |
+ // 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 |