Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2860)

Unified Diff: android_webview/native/aw_contents.cc

Issue 11823027: [Android WebView] Implement the capture picture API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: removing any IPC DCHECKS. Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « android_webview/native/aw_contents.h ('k') | android_webview/public/browser/draw_sw.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: android_webview/native/aw_contents.cc
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index f170e4927ac7041ee9ce4006daaf45e2d441da1d..a7ae2e189a4530057e01b5271d0ed00c697cb947 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_context.h"
@@ -39,10 +40,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/SkGraphics.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/transform.h"
@@ -82,6 +83,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 {
@@ -89,6 +134,7 @@ namespace android_webview {
namespace {
AwDrawSWFunctionTable* g_draw_sw_functions = NULL;
+bool g_is_skia_version_compatible = false;
const void* kAwContentsUserDataKey = &kAwContentsUserDataKey;
@@ -124,6 +170,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 =
@@ -174,7 +221,8 @@ void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
TRACE_EVENT0("AwContents", "AwContents::DrawGL");
- if (!scissor_clip_layer_ || draw_info->mode == AwDrawGLInfo::kModeProcess)
+ if (view_size_.IsEmpty() || !scissor_clip_layer_ ||
+ draw_info->mode == AwDrawGLInfo::kModeProcess)
return;
DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
@@ -388,20 +436,38 @@ 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");
+
+ if (clip_w <= 0 || clip_h <= 0)
+ return true;
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),
@@ -425,11 +491,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) {
@@ -472,6 +538,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);
+ LOG_IF(WARNING, !g_is_skia_version_compatible) <<
+ "Skia native versions are not compatible.";
}
// static
@@ -755,7 +826,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) {
@@ -907,14 +984,105 @@ 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_recordBitmapIntoPicture(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): when SW rendering uses the compositor rather than
+ // picture rasterization, send update the renderer side with the correct
+ // listener state. (For now, we always leave render picture listener enabled).
+ // 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
« no previous file with comments | « android_webview/native/aw_contents.h ('k') | android_webview/public/browser/draw_sw.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698