| 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
|
|
|