blob: 4c43285432460e488ae87bfc8f0b2a146f5ff51e [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/native/java_browser_view_renderer_helper.h"
#include <android/bitmap.h>
#include "android_webview/common/aw_switches.h"
#include "android_webview/public/browser/draw_sw.h"
#include "base/android/scoped_java_ref.h"
#include "base/debug/trace_event.h"
#include "jni/JavaBrowserViewRendererHelper_jni.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/utils/SkCanvasStateUtils.h"
using base::android::ScopedJavaLocalRef;
namespace android_webview {
namespace {
// Provides software rendering functions from the Android glue layer.
// Allows preventing extra copies of data when rendering.
AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
class JavaCanvasHolder : public SoftwareCanvasHolder {
public:
JavaCanvasHolder(JNIEnv* env,
jobject java_canvas,
const gfx::Vector2d& scroll_correction);
~JavaCanvasHolder() override;
SkCanvas* GetCanvas() override;
private:
AwPixelInfo* pixels_;
skia::RefPtr<SkCanvas> canvas_;
DISALLOW_COPY_AND_ASSIGN(JavaCanvasHolder);
};
JavaCanvasHolder::JavaCanvasHolder(JNIEnv* env,
jobject java_canvas,
const gfx::Vector2d& scroll)
: pixels_(nullptr) {
if (!g_sw_draw_functions || switches::ForceAuxiliaryBitmap())
return;
pixels_ = g_sw_draw_functions->access_pixels(env, java_canvas);
if (!pixels_ || !pixels_->state)
return;
canvas_ =
skia::AdoptRef(SkCanvasStateUtils::CreateFromCanvasState(pixels_->state));
// Workarounds for http://crbug.com/271096: SW draw only supports
// translate & scale transforms, and a simple rectangular clip.
if (canvas_ && (!canvas_->isClipRect() ||
(canvas_->getTotalMatrix().getType() &
~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
canvas_.clear();
}
if (canvas_) {
canvas_->translate(scroll.x(), scroll.y());
}
}
JavaCanvasHolder::~JavaCanvasHolder() {
canvas_.clear();
if (pixels_)
g_sw_draw_functions->release_pixels(pixels_);
pixels_ = nullptr;
}
SkCanvas* JavaCanvasHolder::GetCanvas() {
return canvas_.get();
}
class AuxiliaryCanvasHolder : public SoftwareCanvasHolder {
public:
AuxiliaryCanvasHolder(JNIEnv* env,
jobject java_canvas,
const gfx::Vector2d& scroll_correction,
const gfx::Size size);
~AuxiliaryCanvasHolder() override;
SkCanvas* GetCanvas() override;
private:
ScopedJavaLocalRef<jobject> jcanvas_;
ScopedJavaLocalRef<jobject> jbitmap_;
gfx::Vector2d scroll_;
scoped_ptr<SkBitmap> bitmap_;
skia::RefPtr<SkCanvas> canvas_;
DISALLOW_COPY_AND_ASSIGN(AuxiliaryCanvasHolder);
};
AuxiliaryCanvasHolder::AuxiliaryCanvasHolder(
JNIEnv* env,
jobject java_canvas,
const gfx::Vector2d& scroll_correction,
const gfx::Size size)
: jcanvas_(env, java_canvas), scroll_(scroll_correction) {
DCHECK(size.width() > 0);
DCHECK(size.height() > 0);
jbitmap_ = Java_JavaBrowserViewRendererHelper_createBitmap(
env, size.width(), size.height(), jcanvas_.obj());
if (!jbitmap_.obj())
return;
AndroidBitmapInfo bitmap_info;
if (AndroidBitmap_getInfo(env, jbitmap_.obj(), &bitmap_info) < 0) {
LOG(ERROR) << "Error getting java bitmap info.";
return;
}
void* pixels = nullptr;
if (AndroidBitmap_lockPixels(env, jbitmap_.obj(), &pixels) < 0) {
LOG(ERROR) << "Error locking java bitmap pixels.";
return;
}
SkImageInfo info =
SkImageInfo::MakeN32Premul(bitmap_info.width, bitmap_info.height);
bitmap_.reset(new SkBitmap);
bitmap_->installPixels(info, pixels, bitmap_info.stride);
canvas_ = skia::AdoptRef(new SkCanvas(*bitmap_));
}
AuxiliaryCanvasHolder::~AuxiliaryCanvasHolder() {
canvas_.clear();
bitmap_.reset();
JNIEnv* env = base::android::AttachCurrentThread();
if (AndroidBitmap_unlockPixels(env, jbitmap_.obj()) < 0) {
LOG(ERROR) << "Error unlocking java bitmap pixels.";
return;
}
Java_JavaBrowserViewRendererHelper_drawBitmapIntoCanvas(
env, jbitmap_.obj(), jcanvas_.obj(), scroll_.x(), scroll_.y());
}
SkCanvas* AuxiliaryCanvasHolder::GetCanvas() {
return canvas_.get();
}
} // namespace
void RasterHelperSetAwDrawSWFunctionTable(AwDrawSWFunctionTable* table) {
g_sw_draw_functions = table;
}
// static
scoped_ptr<SoftwareCanvasHolder> SoftwareCanvasHolder::Create(
jobject java_canvas,
const gfx::Vector2d& scroll_correction,
const gfx::Size& auxiliary_bitmap_size) {
JNIEnv* env = base::android::AttachCurrentThread();
scoped_ptr<SoftwareCanvasHolder> holder(
new JavaCanvasHolder(env, java_canvas, scroll_correction));
if (!holder->GetCanvas()) {
holder.reset();
holder.reset(new AuxiliaryCanvasHolder(env, java_canvas, scroll_correction,
auxiliary_bitmap_size));
}
if (!holder->GetCanvas()) {
holder.reset();
}
return holder;
}
bool RegisterJavaBrowserViewRendererHelper(JNIEnv* env) {
return RegisterNativesImpl(env);
}
} // namespace android_webview