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..1a4103c66c1fadfb633523df33d9304799486111 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,8 @@ AwContents::AwContents(JNIEnv* env, |
view_visible_(false), |
compositor_visible_(false), |
is_composite_pending_(false), |
+ on_new_picture_enabled_(false), |
+ on_new_picture_invalidation_only_(false), |
last_frame_context_(NULL) { |
RendererPictureMap::CreateInstance(); |
android_webview::AwBrowserDependencyFactory* dependency_factory = |
@@ -379,9 +382,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 |
+ // 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 +467,10 @@ void AwContents::Destroy(JNIEnv* env, jobject obj) { |
void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) { |
g_draw_sw_functions = |
reinterpret_cast<AwDrawSWFunctionTable*>(function_table); |
+ g_is_skia_version_compatible = |
Leandro Graciá Gil
2013/01/10 19:52:47
This needs to be temporarily commented out until t
Leandro Graciá Gil
2013/01/12 17:59:14
Done.
|
+ 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,11 @@ void AwContents::Invalidate() { |
if (obj.is_null()) |
return; |
- Java_AwContents_invalidate(env, obj.obj()); |
+ if (view_visible_) |
+ Java_AwContents_invalidate(env, obj.obj()); |
+ |
+ if (on_new_picture_enabled_ && on_new_picture_invalidation_only_) |
joth
2013/01/12 02:36:28
comment where we do the callback if it's !invalida
Leandro Graciá Gil
2013/01/12 17:59:14
Done.
|
+ Java_AwContents_onNewPicture(env, obj.obj(), NULL); |
} |
void AwContents::SetCompositorVisibility(bool visible) { |
@@ -848,14 +861,119 @@ 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) { |
+ on_new_picture_enabled_ = enabled; |
+ on_new_picture_invalidation_only_ = invalidation_only; |
joth
2013/01/12 02:36:28
I'm wondering if these two would be better as an e
Leandro Graciá Gil
2013/01/12 17:59:14
Done.
|
+ |
+ // If onNewPicture is triggered only on invalidation do not capture |
+ // pictures on every new frame. |
+ if (on_new_picture_invalidation_only_) |
+ return; |
+ |
+ // 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_enabled_ && !on_new_picture_invalidation_only_) { |
+ 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_enabled_) |
+ 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 |