| Index: android_webview/browser/browser_view_renderer_impl.cc
|
| diff --git a/android_webview/browser/browser_view_renderer_impl.cc b/android_webview/browser/browser_view_renderer_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..250cdb0a1292c1d5f38872b015726c06b529939e
|
| --- /dev/null
|
| +++ b/android_webview/browser/browser_view_renderer_impl.cc
|
| @@ -0,0 +1,596 @@
|
| +// 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/browser/browser_view_renderer_impl.h"
|
| +
|
| +#include <android/bitmap.h>
|
| +#include <sys/system_properties.h>
|
| +
|
| +#include "android_webview/common/renderer_picture_map.h"
|
| +#include "android_webview/public/browser/draw_gl.h"
|
| +#include "android_webview/public/browser/draw_sw.h"
|
| +#include "base/android/jni_android.h"
|
| +#include "base/debug/trace_event.h"
|
| +#include "base/logging.h"
|
| +#include "cc/layer.h"
|
| +#include "content/public/browser/android/content_view_core.h"
|
| +#include "content/public/browser/render_process_host.h"
|
| +#include "content/public/browser/web_contents.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 "ui/gfx/size.h"
|
| +#include "ui/gfx/transform.h"
|
| +#include "ui/gl/gl_bindings.h"
|
| +
|
| +// TODO(leandrogracia): remove when crbug.com/164140 is closed.
|
| +// Borrowed from gl2ext.h. Cannot be included due to conflicts with
|
| +// gl_bindings.h and the EGL library methods (eglGetCurrentContext).
|
| +#ifndef GL_TEXTURE_EXTERNAL_OES
|
| +#define GL_TEXTURE_EXTERNAL_OES 0x8D65
|
| +#endif
|
| +
|
| +#ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
|
| +#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
|
| +#endif
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::JavaRef;
|
| +using base::android::ScopedJavaLocalRef;
|
| +using content::Compositor;
|
| +using content::ContentViewCore;
|
| +
|
| +namespace {
|
| +
|
| +// Provides software rendering functions from the Android glue layer.
|
| +// Allows preventing extra copies of data when rendering.
|
| +AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
|
| +
|
| +// Tells if the Skia library versions in Android and Chromium are compatible.
|
| +// If they are then it's possible to pass Skia objects like SkPictures to the
|
| +// Android glue layer via the SW rendering functions.
|
| +// If they are not, then additional copies and rasterizations are required
|
| +// as a fallback mechanism, which will have an important performance impact.
|
| +bool g_is_skia_version_compatible = false;
|
| +
|
| +typedef base::Callback<bool(SkCanvas*)> RenderMethod;
|
| +
|
| +static bool RasterizeIntoBitmap(JNIEnv* env,
|
| + const JavaRef<jobject>& jbitmap,
|
| + int scroll_x,
|
| + int scroll_y,
|
| + const RenderMethod& renderer) {
|
| + DCHECK(jbitmap.obj());
|
| +
|
| + AndroidBitmapInfo bitmap_info;
|
| + if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
|
| + LOG(ERROR) << "Error getting java bitmap info.";
|
| + return false;
|
| + }
|
| +
|
| + void* pixels = NULL;
|
| + if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
|
| + LOG(ERROR) << "Error locking java bitmap pixels.";
|
| + return false;
|
| + }
|
| +
|
| + bool succeeded;
|
| + {
|
| + 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.obj()) < 0) {
|
| + LOG(ERROR) << "Error unlocking java bitmap pixels.";
|
| + return false;
|
| + }
|
| +
|
| + return succeeded;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace android_webview {
|
| +
|
| +// static
|
| +BrowserViewRendererImpl* BrowserViewRendererImpl::Create(
|
| + BrowserViewRenderer::Client* client,
|
| + JavaHelper* java_helper) {
|
| + return new BrowserViewRendererImpl(client, java_helper);
|
| +}
|
| +
|
| +BrowserViewRendererImpl::BrowserViewRendererImpl(
|
| + BrowserViewRenderer::Client* client,
|
| + JavaHelper* java_helper)
|
| + : client_(client),
|
| + java_helper_(java_helper),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(compositor_(Compositor::Create(this))),
|
| + view_clip_layer_(cc::Layer::create()),
|
| + transform_layer_(cc::Layer::create()),
|
| + scissor_clip_layer_(cc::Layer::create()),
|
| + view_visible_(false),
|
| + compositor_visible_(false),
|
| + is_composite_pending_(false),
|
| + dpi_scale_(1.0f),
|
| + on_new_picture_mode_(kOnNewPictureDisabled),
|
| + last_frame_context_(NULL),
|
| + web_contents_(NULL) {
|
| + DCHECK(java_helper);
|
| +
|
| + // Define the view hierarchy.
|
| + transform_layer_->addChild(view_clip_layer_);
|
| + scissor_clip_layer_->addChild(transform_layer_);
|
| + compositor_->SetRootLayer(scissor_clip_layer_);
|
| +
|
| + RendererPictureMap::CreateInstance();
|
| +}
|
| +
|
| +BrowserViewRendererImpl::~BrowserViewRendererImpl() {
|
| +}
|
| +
|
| +// static
|
| +void BrowserViewRendererImpl::SetAwDrawSWFunctionTable(
|
| + AwDrawSWFunctionTable* table) {
|
| + g_sw_draw_functions = table;
|
| + g_is_skia_version_compatible =
|
| + g_sw_draw_functions->is_skia_version_compatible(&SkGraphics::GetVersion);
|
| + LOG_IF(WARNING, !g_is_skia_version_compatible)
|
| + << "Skia versions are not compatible, rendering performance will suffer.";
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::SetContents(ContentViewCore* content_view_core) {
|
| + dpi_scale_ = content_view_core->GetDpiScale();
|
| + web_contents_ = content_view_core->GetWebContents();
|
| + if (!view_renderer_host_)
|
| + view_renderer_host_.reset(new ViewRendererHost(web_contents_, this));
|
| + else
|
| + view_renderer_host_->Observe(web_contents_);
|
| +
|
| + view_clip_layer_->removeAllChildren();
|
| + view_clip_layer_->addChild(content_view_core->GetLayer());
|
| + Invalidate();
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::DrawGL(AwDrawGLInfo* draw_info) {
|
| + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawGL");
|
| +
|
| + if (view_size_.IsEmpty() || !scissor_clip_layer_ ||
|
| + draw_info->mode == AwDrawGLInfo::kModeProcess)
|
| + return;
|
| +
|
| + DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
|
| +
|
| + SetCompositorVisibility(view_visible_);
|
| + if (!compositor_visible_)
|
| + return;
|
| +
|
| + // TODO(leandrogracia): remove when crbug.com/164140 is closed.
|
| + // ---------------------------------------------------------------------------
|
| + GLint texture_external_oes_binding;
|
| + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_external_oes_binding);
|
| +
|
| + GLint vertex_array_buffer_binding;
|
| + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding);
|
| +
|
| + GLint index_array_buffer_binding;
|
| + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding);
|
| +
|
| + GLint pack_alignment;
|
| + glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
|
| +
|
| + GLint unpack_alignment;
|
| + glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
|
| +
|
| + struct {
|
| + GLint enabled;
|
| + GLint size;
|
| + GLint type;
|
| + GLint normalized;
|
| + GLint stride;
|
| + GLvoid* pointer;
|
| + } vertex_attrib[3];
|
| +
|
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
|
| + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
|
| + &vertex_attrib[i].enabled);
|
| + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE,
|
| + &vertex_attrib[i].size);
|
| + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE,
|
| + &vertex_attrib[i].type);
|
| + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
|
| + &vertex_attrib[i].normalized);
|
| + glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE,
|
| + &vertex_attrib[i].stride);
|
| + glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER,
|
| + &vertex_attrib[i].pointer);
|
| + }
|
| +
|
| + GLboolean depth_test;
|
| + glGetBooleanv(GL_DEPTH_TEST, &depth_test);
|
| +
|
| + GLboolean cull_face;
|
| + glGetBooleanv(GL_CULL_FACE, &cull_face);
|
| +
|
| + GLboolean color_mask[4];
|
| + glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
|
| +
|
| + GLboolean blend_enabled;
|
| + glGetBooleanv(GL_BLEND, &blend_enabled);
|
| +
|
| + GLint blend_src_rgb;
|
| + glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
|
| +
|
| + GLint blend_src_alpha;
|
| + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
|
| +
|
| + GLint blend_dest_rgb;
|
| + glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb);
|
| +
|
| + GLint blend_dest_alpha;
|
| + glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha);
|
| +
|
| + GLint active_texture;
|
| + glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
|
| +
|
| + GLint viewport[4];
|
| + glGetIntegerv(GL_VIEWPORT, viewport);
|
| +
|
| + GLboolean scissor_test;
|
| + glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
|
| +
|
| + GLint scissor_box[4];
|
| + glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
|
| +
|
| + GLint current_program;
|
| + glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program);
|
| + // ---------------------------------------------------------------------------
|
| +
|
| + // We need to watch if the current Android context has changed and enforce
|
| + // a clean-up in the compositor.
|
| + EGLContext current_context = eglGetCurrentContext();
|
| + if (!current_context) {
|
| + LOG(WARNING) << "No current context attached. Skipping composite.";
|
| + return;
|
| + }
|
| +
|
| + if (last_frame_context_ != current_context) {
|
| + if (last_frame_context_)
|
| + ResetCompositor();
|
| + last_frame_context_ = current_context;
|
| + }
|
| +
|
| + compositor_->SetWindowBounds(gfx::Size(draw_info->width, draw_info->height));
|
| +
|
| + if (draw_info->is_layer) {
|
| + // When rendering into a separate layer no view clipping, transform,
|
| + // scissoring or background transparency need to be handled.
|
| + // The Android framework will composite us afterwards.
|
| + compositor_->SetHasTransparentBackground(false);
|
| + view_clip_layer_->setMasksToBounds(false);
|
| + transform_layer_->setTransform(gfx::Transform());
|
| + scissor_clip_layer_->setMasksToBounds(false);
|
| + scissor_clip_layer_->setPosition(gfx::PointF());
|
| + scissor_clip_layer_->setBounds(gfx::Size());
|
| + scissor_clip_layer_->setSublayerTransform(gfx::Transform());
|
| +
|
| + } else {
|
| + compositor_->SetHasTransparentBackground(true);
|
| +
|
| + gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top,
|
| + draw_info->clip_right - draw_info->clip_left,
|
| + draw_info->clip_bottom - draw_info->clip_top);
|
| +
|
| + scissor_clip_layer_->setPosition(clip_rect.origin());
|
| + scissor_clip_layer_->setBounds(clip_rect.size());
|
| + scissor_clip_layer_->setMasksToBounds(true);
|
| +
|
| + // The compositor clipping architecture enforces us to have the clip layer
|
| + // as an ancestor of the area we want to clip, but this makes the transform
|
| + // become relative to the clip area rather than the full surface. The clip
|
| + // position offset needs to be undone before applying the transform.
|
| + gfx::Transform undo_clip_position;
|
| + undo_clip_position.Translate(-clip_rect.x(), -clip_rect.y());
|
| + scissor_clip_layer_->setSublayerTransform(undo_clip_position);
|
| +
|
| + gfx::Transform transform;
|
| + transform.matrix().setColMajorf(draw_info->transform);
|
| +
|
| + // The scrolling values of the Android Framework affect the transformation
|
| + // matrix. This needs to be undone to let the compositor handle scrolling.
|
| + // TODO(leandrogracia): when scrolling becomes synchronous we should undo
|
| + // or override the translation in the compositor, not the one coming from
|
| + // the Android View System, as it could be out of bounds for overscrolling.
|
| + transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y());
|
| + transform_layer_->setTransform(transform);
|
| +
|
| + view_clip_layer_->setMasksToBounds(true);
|
| + }
|
| +
|
| + compositor_->Composite();
|
| + is_composite_pending_ = false;
|
| +
|
| + // TODO(leandrogracia): remove when crbug.com/164140 is closed.
|
| + // ---------------------------------------------------------------------------
|
| + char no_gl_restore_prop[PROP_VALUE_MAX];
|
| + __system_property_get("webview.chromium_no_gl_restore", no_gl_restore_prop);
|
| + if (!strcmp(no_gl_restore_prop, "true")) {
|
| + LOG(WARNING) << "Android GL functor not restoring the previous GL state.";
|
| + } else {
|
| + glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding);
|
| + glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding);
|
| + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding);
|
| +
|
| + glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
|
| + glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
|
| +
|
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
|
| + glVertexAttribPointer(i, vertex_attrib[i].size,
|
| + vertex_attrib[i].type, vertex_attrib[i].normalized,
|
| + vertex_attrib[i].stride, vertex_attrib[i].pointer);
|
| +
|
| + if (vertex_attrib[i].enabled)
|
| + glEnableVertexAttribArray(i);
|
| + else
|
| + glDisableVertexAttribArray(i);
|
| + }
|
| +
|
| + if (depth_test)
|
| + glEnable(GL_DEPTH_TEST);
|
| + else
|
| + glDisable(GL_DEPTH_TEST);
|
| +
|
| + if (cull_face)
|
| + glEnable(GL_CULL_FACE);
|
| + else
|
| + glDisable(GL_CULL_FACE);
|
| +
|
| + glColorMask(color_mask[0], color_mask[1], color_mask[2], color_mask[3]);
|
| +
|
| + if (blend_enabled)
|
| + glEnable(GL_BLEND);
|
| + else
|
| + glDisable(GL_BLEND);
|
| +
|
| + glBlendFuncSeparate(blend_src_rgb, blend_dest_rgb,
|
| + blend_src_alpha, blend_dest_alpha);
|
| +
|
| + glActiveTexture(active_texture);
|
| +
|
| + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
| +
|
| + if (scissor_test)
|
| + glEnable(GL_SCISSOR_TEST);
|
| + else
|
| + glDisable(GL_SCISSOR_TEST);
|
| +
|
| + glScissor(scissor_box[0], scissor_box[1], scissor_box[2],
|
| + scissor_box[3]);
|
| +
|
| + glUseProgram(current_program);
|
| + }
|
| + // ---------------------------------------------------------------------------
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::SetScrollForHWFrame(int x, int y) {
|
| + hw_rendering_scroll_ = gfx::Point(x, y);
|
| +}
|
| +
|
| +bool BrowserViewRendererImpl::DrawSW(jobject java_canvas,
|
| + const gfx::Rect& clip) {
|
| + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawSW");
|
| +
|
| + if (clip.IsEmpty())
|
| + return true;
|
| +
|
| + AwPixelInfo* pixels;
|
| + JNIEnv* env = AttachCurrentThread();
|
| +
|
| + // Render into an auxiliary bitmap if pixel info is not available.
|
| + if (!g_sw_draw_functions ||
|
| + (pixels = g_sw_draw_functions->access_pixels(env, java_canvas)) == NULL) {
|
| + ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
|
| + env, clip.width(), clip.height()));
|
| + if (!jbitmap.obj())
|
| + return false;
|
| +
|
| + if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(),
|
| + base::Bind(&BrowserViewRendererImpl::RenderSW,
|
| + base::Unretained(this)))) {
|
| + return false;
|
| + }
|
| +
|
| + ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
|
| + java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas);
|
| + return true;
|
| + }
|
| +
|
| + // Draw in a SkCanvas built over the pixel information.
|
| + bool succeeded = false;
|
| + {
|
| + SkBitmap bitmap;
|
| + bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
|
| + pixels->width,
|
| + pixels->height,
|
| + pixels->row_bytes);
|
| + bitmap.setPixels(pixels->pixels);
|
| + SkDevice device(bitmap);
|
| + SkCanvas canvas(&device);
|
| + SkMatrix matrix;
|
| + for (int i = 0; i < 9; i++)
|
| + matrix.set(i, pixels->matrix[i]);
|
| + canvas.setMatrix(matrix);
|
| +
|
| + SkRegion clip;
|
| + if (pixels->clip_region_size) {
|
| + size_t bytes_read = clip.readFromMemory(pixels->clip_region);
|
| + DCHECK_EQ(pixels->clip_region_size, bytes_read);
|
| + canvas.setClipRegion(clip);
|
| + } else {
|
| + clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height));
|
| + }
|
| +
|
| + succeeded = RenderSW(&canvas);
|
| + }
|
| +
|
| + g_sw_draw_functions->release_pixels(pixels);
|
| + return succeeded;
|
| +}
|
| +
|
| +ScopedJavaLocalRef<jobject> BrowserViewRendererImpl::CapturePicture() {
|
| + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture();
|
| + if (!picture || !g_sw_draw_functions)
|
| + return ScopedJavaLocalRef<jobject>();
|
| +
|
| + JNIEnv* env = AttachCurrentThread();
|
| + if (g_is_skia_version_compatible) {
|
| + return ScopedJavaLocalRef<jobject>(env,
|
| + g_sw_draw_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_helper_->CreateBitmap(
|
| + env, picture->width(), picture->height()));
|
| + if (!jbitmap.obj())
|
| + return ScopedJavaLocalRef<jobject>();
|
| +
|
| + if (!RasterizeIntoBitmap(env, jbitmap, 0, 0,
|
| + base::Bind(&BrowserViewRendererImpl::RenderPicture,
|
| + base::Unretained(this)))) {
|
| + return ScopedJavaLocalRef<jobject>();
|
| + }
|
| +
|
| + return java_helper_->RecordBitmapIntoPicture(env, jbitmap);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::EnableOnNewPicture(OnNewPictureMode mode) {
|
| + on_new_picture_mode_ = mode;
|
| +
|
| + // 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);
|
| + //DCHECK(view_renderer_host_);
|
| + //view_renderer_host_->EnableCapturePictureCallback(
|
| + // on_new_picture_mode_ == kOnNewPictureEnabled);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::OnVisibilityChanged(bool view_visible,
|
| + bool window_visible) {
|
| + view_visible_ = window_visible && view_visible;
|
| + Invalidate();
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::OnSizeChanged(int width, int height) {
|
| + view_size_ = gfx::Size(width, height);
|
| + view_clip_layer_->setBounds(view_size_);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::OnAttachedToWindow(int width, int height) {
|
| + view_size_ = gfx::Size(width, height);
|
| + view_clip_layer_->setBounds(view_size_);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::OnDetachedFromWindow() {
|
| + view_visible_ = false;
|
| + SetCompositorVisibility(false);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::ScheduleComposite() {
|
| + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::ScheduleComposite");
|
| +
|
| + if (is_composite_pending_)
|
| + return;
|
| +
|
| + is_composite_pending_ = true;
|
| + Invalidate();
|
| +}
|
| +
|
| +skia::RefPtr<SkPicture> BrowserViewRendererImpl::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) {
|
| + DCHECK(view_renderer_host_);
|
| + view_renderer_host_->CapturePictureSync();
|
| + picture = RendererPictureMap::GetInstance()->GetRendererPicture(
|
| + web_contents_->GetRoutingID());
|
| + }
|
| +
|
| + return picture;
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::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)
|
| + client_->OnNewPicture(CapturePicture());
|
| +
|
| + // TODO(leandrogracia): delete when sw rendering uses Ubercompositor.
|
| + // Invalidation should be provided by the compositor only.
|
| + Invalidate();
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::SetCompositorVisibility(bool visible) {
|
| + if (compositor_visible_ != visible) {
|
| + compositor_visible_ = visible;
|
| + compositor_->SetVisible(compositor_visible_);
|
| + }
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::ResetCompositor() {
|
| + compositor_.reset(content::Compositor::Create(this));
|
| + compositor_->SetRootLayer(scissor_clip_layer_);
|
| +}
|
| +
|
| +void BrowserViewRendererImpl::Invalidate() {
|
| + if (view_visible_)
|
| + client_->Invalidate();
|
| +
|
| + // When not in invalidation-only mode onNewPicture will be triggered
|
| + // from the OnPictureUpdated callback.
|
| + if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly)
|
| + client_->OnNewPicture(ScopedJavaLocalRef<jobject>());
|
| +}
|
| +
|
| +bool BrowserViewRendererImpl::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 BrowserViewRendererImpl::RenderPicture(SkCanvas* canvas) {
|
| + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture();
|
| + if (!picture)
|
| + return false;
|
| +
|
| + // Correct device scale.
|
| + canvas->scale(dpi_scale_, dpi_scale_);
|
| +
|
| + picture->draw(canvas);
|
| + return true;
|
| +}
|
| +
|
| +} // namespace android_webview
|
|
|