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

Side by Side Diff: android_webview/browser/browser_view_renderer_impl.cc

Issue 16796002: Delete the browser-compositor webview render mode (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "android_webview/browser/browser_view_renderer_impl.h"
6
7 #include <android/bitmap.h>
8
9 #include "android_webview/browser/in_process_view_renderer.h"
10 #include "android_webview/common/aw_switches.h"
11 #include "android_webview/common/renderer_picture_map.h"
12 #include "android_webview/public/browser/draw_gl.h"
13 #include "android_webview/public/browser/draw_sw.h"
14 #include "base/android/jni_android.h"
15 #include "base/command_line.h"
16 #include "base/debug/trace_event.h"
17 #include "base/logging.h"
18 #include "cc/layers/layer.h"
19 #include "content/public/browser/android/content_view_core.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "third_party/skia/include/core/SkBitmap.h"
24 #include "third_party/skia/include/core/SkCanvas.h"
25 #include "third_party/skia/include/core/SkDevice.h"
26 #include "third_party/skia/include/core/SkGraphics.h"
27 #include "ui/gfx/size_conversions.h"
28 #include "ui/gfx/transform.h"
29 #include "ui/gfx/vector2d_f.h"
30 #include "ui/gl/gl_bindings.h"
31
32 using base::android::AttachCurrentThread;
33 using base::android::JavaRef;
34 using base::android::ScopedJavaLocalRef;
35 using content::Compositor;
36 using content::ContentViewCore;
37
38 namespace android_webview {
39
40 namespace {
41
42 // Provides software rendering functions from the Android glue layer.
43 // Allows preventing extra copies of data when rendering.
44 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
45
46 // Tells if the Skia library versions in Android and Chromium are compatible.
47 // If they are then it's possible to pass Skia objects like SkPictures to the
48 // Android glue layer via the SW rendering functions.
49 // If they are not, then additional copies and rasterizations are required
50 // as a fallback mechanism, which will have an important performance impact.
51 bool g_is_skia_version_compatible = false;
52
53 typedef base::Callback<bool(SkCanvas*)> RenderMethod;
54
55 bool RasterizeIntoBitmap(JNIEnv* env,
56 const JavaRef<jobject>& jbitmap,
57 int scroll_x,
58 int scroll_y,
59 const RenderMethod& renderer) {
60 DCHECK(jbitmap.obj());
61
62 AndroidBitmapInfo bitmap_info;
63 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
64 LOG(ERROR) << "Error getting java bitmap info.";
65 return false;
66 }
67
68 void* pixels = NULL;
69 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
70 LOG(ERROR) << "Error locking java bitmap pixels.";
71 return false;
72 }
73
74 bool succeeded;
75 {
76 SkBitmap bitmap;
77 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
78 bitmap_info.width,
79 bitmap_info.height,
80 bitmap_info.stride);
81 bitmap.setPixels(pixels);
82
83 SkDevice device(bitmap);
84 SkCanvas canvas(&device);
85 canvas.translate(-scroll_x, -scroll_y);
86 succeeded = renderer.Run(&canvas);
87 }
88
89 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
90 LOG(ERROR) << "Error unlocking java bitmap pixels.";
91 return false;
92 }
93
94 return succeeded;
95 }
96
97 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
98 canvas->drawPicture(*picture);
99 return true;
100 }
101
102 const void* kUserDataKey = &kUserDataKey;
103
104 } // namespace
105
106 class BrowserViewRendererImpl::UserData : public content::WebContents::Data {
107 public:
108 UserData(BrowserViewRendererImpl* ptr) : instance_(ptr) {}
109 virtual ~UserData() {
110 instance_->WebContentsGone();
111 }
112
113 static BrowserViewRendererImpl* GetInstance(content::WebContents* contents) {
114 if (!contents)
115 return NULL;
116 UserData* data = reinterpret_cast<UserData*>(
117 contents->GetUserData(kUserDataKey));
118 return data ? data->instance_ : NULL;
119 }
120
121 private:
122 BrowserViewRendererImpl* instance_;
123 };
124
125 // static
126 BrowserViewRenderer* BrowserViewRendererImpl::Create(
127 BrowserViewRenderer::Client* client,
128 JavaHelper* java_helper) {
129 if (CommandLine::ForCurrentProcess()->HasSwitch(
130 switches::kNoMergeUIAndRendererCompositorThreads)) {
131 return new BrowserViewRendererImpl(client, java_helper);
132 }
133
134 return new InProcessViewRenderer(client, java_helper);
135 }
136
137 // static
138 BrowserViewRendererImpl* BrowserViewRendererImpl::FromWebContents(
139 content::WebContents* contents) {
140 return UserData::GetInstance(contents);
141 }
142
143 BrowserViewRendererImpl::BrowserViewRendererImpl(
144 BrowserViewRenderer::Client* client,
145 JavaHelper* java_helper)
146 : client_(client),
147 java_helper_(java_helper),
148 view_renderer_host_(new ViewRendererHost(NULL, this)),
149 compositor_(Compositor::Create(this)),
150 view_clip_layer_(cc::Layer::Create()),
151 transform_layer_(cc::Layer::Create()),
152 scissor_clip_layer_(cc::Layer::Create()),
153 view_attached_(false),
154 view_visible_(false),
155 compositor_visible_(false),
156 is_composite_pending_(false),
157 dpi_scale_(1.0f),
158 page_scale_(1.0f),
159 new_picture_enabled_(false),
160 last_frame_context_(NULL),
161 web_contents_(NULL),
162 update_frame_info_callback_(
163 base::Bind(&BrowserViewRendererImpl::OnFrameInfoUpdated,
164 base::Unretained(this))),
165 prevent_client_invalidate_(false) {
166
167 DCHECK(java_helper);
168
169 // Define the view hierarchy.
170 transform_layer_->AddChild(view_clip_layer_);
171 scissor_clip_layer_->AddChild(transform_layer_);
172 compositor_->SetRootLayer(scissor_clip_layer_);
173
174 RendererPictureMap::CreateInstance();
175 }
176
177 BrowserViewRendererImpl::~BrowserViewRendererImpl() {
178 SetContents(NULL);
179 }
180
181 // static
182 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
183 AwDrawSWFunctionTable* table) {
184 g_sw_draw_functions = table;
185 g_is_skia_version_compatible =
186 g_sw_draw_functions->is_skia_version_compatible(&SkGraphics::GetVersion);
187 LOG_IF(WARNING, !g_is_skia_version_compatible)
188 << "Skia versions are not compatible, rendering performance will suffer.";
189 }
190
191 // static
192 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
193 return g_sw_draw_functions;
194 }
195
196 // static
197 bool BrowserViewRenderer::IsSkiaVersionCompatible() {
198 DCHECK(g_sw_draw_functions);
199 return g_is_skia_version_compatible;
200 }
201
202 void BrowserViewRendererImpl::SetContents(ContentViewCore* content_view_core) {
203 // First remove association from the prior ContentViewCore / WebContents.
204 if (web_contents_) {
205 ContentViewCore* previous_content_view_core =
206 ContentViewCore::FromWebContents(web_contents_);
207 if (previous_content_view_core) {
208 previous_content_view_core->RemoveFrameInfoCallback(
209 update_frame_info_callback_);
210 }
211 web_contents_->SetUserData(kUserDataKey, NULL);
212 DCHECK(!web_contents_); // WebContentsGone should have been called.
213 }
214
215 if (!content_view_core)
216 return;
217
218 web_contents_ = content_view_core->GetWebContents();
219 web_contents_->SetUserData(kUserDataKey, new UserData(this));
220 view_renderer_host_->Observe(web_contents_);
221
222 content_view_core->AddFrameInfoCallback(update_frame_info_callback_);
223 dpi_scale_ = content_view_core->GetDpiScale();
224
225 view_clip_layer_->RemoveAllChildren();
226 view_clip_layer_->AddChild(content_view_core->GetLayer());
227 Invalidate();
228 }
229
230 void BrowserViewRendererImpl::WebContentsGone() {
231 web_contents_ = NULL;
232 }
233
234 bool BrowserViewRendererImpl::PrepareDrawGL(int x, int y) {
235 hw_rendering_scroll_ = gfx::Point(x, y);
236 return true;
237 }
238
239 void BrowserViewRendererImpl::DrawGL(AwDrawGLInfo* draw_info) {
240 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawGL");
241
242 if (view_size_.IsEmpty() || !scissor_clip_layer_ ||
243 draw_info->mode == AwDrawGLInfo::kModeProcess)
244 return;
245
246 DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
247
248 SetCompositorVisibility(view_visible_);
249 if (!compositor_visible_)
250 return;
251
252 // We need to watch if the current Android context has changed and enforce
253 // a clean-up in the compositor.
254 EGLContext current_context = eglGetCurrentContext();
255 if (!current_context) {
256 LOG(WARNING) << "No current context attached. Skipping composite.";
257 return;
258 }
259
260 if (last_frame_context_ != current_context) {
261 if (last_frame_context_)
262 ResetCompositor();
263 last_frame_context_ = current_context;
264 }
265
266 compositor_->SetWindowBounds(gfx::Size(draw_info->width, draw_info->height));
267
268 // We need to trigger a compositor invalidate because otherwise, if nothing
269 // has changed since last draw the compositor will early out (Android may
270 // trigger a draw at anytime). However, we don't want to trigger a client
271 // (i.e. Android View system) invalidate as a result of this (otherwise we'll
272 // end up in a loop of DrawGL calls).
273 prevent_client_invalidate_ = true;
274 compositor_->SetNeedsRedraw();
275 prevent_client_invalidate_ = false;
276
277 if (draw_info->is_layer) {
278 // When rendering into a separate layer no view clipping, transform,
279 // scissoring or background transparency need to be handled.
280 // The Android framework will composite us afterwards.
281 compositor_->SetHasTransparentBackground(false);
282 view_clip_layer_->SetMasksToBounds(false);
283 transform_layer_->SetTransform(gfx::Transform());
284 scissor_clip_layer_->SetMasksToBounds(false);
285 scissor_clip_layer_->SetPosition(gfx::PointF());
286 scissor_clip_layer_->SetBounds(gfx::Size());
287 scissor_clip_layer_->SetSublayerTransform(gfx::Transform());
288
289 } else {
290 compositor_->SetHasTransparentBackground(true);
291
292 gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top,
293 draw_info->clip_right - draw_info->clip_left,
294 draw_info->clip_bottom - draw_info->clip_top);
295
296 scissor_clip_layer_->SetPosition(clip_rect.origin());
297 scissor_clip_layer_->SetBounds(clip_rect.size());
298 scissor_clip_layer_->SetMasksToBounds(true);
299
300 // The compositor clipping architecture enforces us to have the clip layer
301 // as an ancestor of the area we want to clip, but this makes the transform
302 // become relative to the clip area rather than the full surface. The clip
303 // position offset needs to be undone before applying the transform.
304 gfx::Transform undo_clip_position;
305 undo_clip_position.Translate(-clip_rect.x(), -clip_rect.y());
306 scissor_clip_layer_->SetSublayerTransform(undo_clip_position);
307
308 gfx::Transform transform;
309 transform.matrix().setColMajorf(draw_info->transform);
310
311 // The scrolling values of the Android Framework affect the transformation
312 // matrix. This needs to be undone to let the compositor handle scrolling.
313 // TODO(leandrogracia): when scrolling becomes synchronous we should undo
314 // or override the translation in the compositor, not the one coming from
315 // the Android View System, as it could be out of bounds for overscrolling.
316 transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y());
317 transform_layer_->SetTransform(transform);
318
319 view_clip_layer_->SetMasksToBounds(true);
320 }
321
322 compositor_->Composite();
323 is_composite_pending_ = false;
324
325 // The GL functor must ensure these are set to zero before returning.
326 // Not setting them leads to graphical artifacts that can affect other apps.
327 glBindBuffer(GL_ARRAY_BUFFER, 0);
328 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
329 }
330
331 bool BrowserViewRendererImpl::DrawSW(jobject java_canvas,
332 const gfx::Rect& clip) {
333 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawSW");
334
335 if (clip.IsEmpty())
336 return true;
337
338 AwPixelInfo* pixels;
339 JNIEnv* env = AttachCurrentThread();
340
341 // Render into an auxiliary bitmap if pixel info is not available.
342 if (!g_sw_draw_functions ||
343 (pixels = g_sw_draw_functions->access_pixels(env, java_canvas)) == NULL) {
344 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
345 env, clip.width(), clip.height(), true));
346 if (!jbitmap.obj())
347 return false;
348
349 if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(),
350 base::Bind(&BrowserViewRendererImpl::RenderSW,
351 base::Unretained(this)))) {
352 return false;
353 }
354
355 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
356 java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
357 clip.x(), clip.y());
358 return true;
359 }
360
361 // Draw in a SkCanvas built over the pixel information.
362 bool succeeded = false;
363 {
364 SkBitmap bitmap;
365 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
366 pixels->width,
367 pixels->height,
368 pixels->row_bytes);
369 bitmap.setPixels(pixels->pixels);
370 SkDevice device(bitmap);
371 SkCanvas canvas(&device);
372 SkMatrix matrix;
373 for (int i = 0; i < 9; i++)
374 matrix.set(i, pixels->matrix[i]);
375 canvas.setMatrix(matrix);
376
377 SkRegion clip;
378 if (pixels->clip_region_size) {
379 size_t bytes_read = clip.readFromMemory(pixels->clip_region);
380 DCHECK_EQ(pixels->clip_region_size, bytes_read);
381 canvas.setClipRegion(clip);
382 } else {
383 clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height));
384 }
385
386 succeeded = RenderSW(&canvas);
387 }
388
389 g_sw_draw_functions->release_pixels(pixels);
390 return succeeded;
391 }
392
393 ScopedJavaLocalRef<jobject> BrowserViewRendererImpl::CapturePicture() {
394 if (!g_sw_draw_functions)
395 return ScopedJavaLocalRef<jobject>();
396
397 gfx::Size record_size = ToCeiledSize(content_size_css_);
398
399 // Return empty Picture objects for empty SkPictures.
400 JNIEnv* env = AttachCurrentThread();
401 if (record_size.width() <= 0 || record_size.height() <= 0) {
402 return java_helper_->RecordBitmapIntoPicture(
403 env, ScopedJavaLocalRef<jobject>());
404 }
405
406 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
407 SkCanvas* rec_canvas = picture->beginRecording(record_size.width(),
408 record_size.height(),
409 0);
410 if (!RenderPicture(rec_canvas))
411 return ScopedJavaLocalRef<jobject>();
412 picture->endRecording();
413
414 if (g_is_skia_version_compatible) {
415 // Add a reference that the create_picture() will take ownership of.
416 picture->ref();
417 return ScopedJavaLocalRef<jobject>(env,
418 g_sw_draw_functions->create_picture(env, picture.get()));
419 }
420
421 // If Skia versions are not compatible, workaround it by rasterizing the
422 // picture into a bitmap and drawing it into a new Java picture.
423 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
424 env, picture->width(), picture->height(), false));
425 if (!jbitmap.obj())
426 return ScopedJavaLocalRef<jobject>();
427
428 if (!RasterizeIntoBitmap(env, jbitmap, 0, 0,
429 base::Bind(&RenderPictureToCanvas,
430 base::Unretained(picture.get())))) {
431 return ScopedJavaLocalRef<jobject>();
432 }
433
434 return java_helper_->RecordBitmapIntoPicture(env, jbitmap);
435 }
436
437 void BrowserViewRendererImpl::EnableOnNewPicture(bool enabled) {
438 new_picture_enabled_ = enabled;
439
440 // TODO(leandrogracia): when SW rendering uses the compositor rather than
441 // picture rasterization, send update the renderer side with the correct
442 // listener state. (For now, we always leave render picture listener enabled).
443 // render_view_host_ext_->EnableCapturePictureCallback(enabled);
444 // http://crbug.com/176945
445 }
446
447 void BrowserViewRendererImpl::OnVisibilityChanged(bool view_visible,
448 bool window_visible) {
449 view_visible_ = window_visible && view_visible;
450 Invalidate();
451 }
452
453 void BrowserViewRendererImpl::OnSizeChanged(int width, int height) {
454 view_size_ = gfx::Size(width, height);
455 view_clip_layer_->SetBounds(view_size_);
456 }
457
458 void BrowserViewRendererImpl::OnAttachedToWindow(int width, int height) {
459 view_attached_ = true;
460 view_size_ = gfx::Size(width, height);
461 view_clip_layer_->SetBounds(view_size_);
462 }
463
464 void BrowserViewRendererImpl::OnDetachedFromWindow() {
465 view_attached_ = false;
466 view_visible_ = false;
467 SetCompositorVisibility(false);
468 }
469
470 bool BrowserViewRendererImpl::IsAttachedToWindow() {
471 return view_attached_;
472 }
473
474 bool BrowserViewRendererImpl::IsViewVisible() {
475 return view_visible_;
476 }
477
478 gfx::Rect BrowserViewRendererImpl::GetScreenRect() {
479 return gfx::Rect(client_->GetLocationOnScreen(), view_size_);
480 }
481
482 void BrowserViewRendererImpl::ScheduleComposite() {
483 TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::ScheduleComposite");
484
485 if (is_composite_pending_)
486 return;
487
488 is_composite_pending_ = true;
489
490 if (!prevent_client_invalidate_)
491 Invalidate();
492 }
493
494 skia::RefPtr<SkPicture> BrowserViewRendererImpl::GetLastCapturedPicture() {
495 // Use the latest available picture if the listener callback is enabled.
496 skia::RefPtr<SkPicture> picture =
497 RendererPictureMap::GetInstance()->GetRendererPicture(
498 web_contents_->GetRoutingID());
499 if (picture) return picture;
500
501 // Get it synchronously.
502 view_renderer_host_->CapturePictureSync();
503 return RendererPictureMap::GetInstance()->GetRendererPicture(
504 web_contents_->GetRoutingID());
505 }
506
507 void BrowserViewRendererImpl::OnPictureUpdated(int process_id,
508 int render_view_id) {
509 CHECK_EQ(web_contents_->GetRenderProcessHost()->GetID(), process_id);
510 if (render_view_id != web_contents_->GetRoutingID())
511 return;
512
513 client_->OnNewPicture();
514
515 // TODO(mkosiba): Remove when invalidation path is re-implemented.
516 Invalidate();
517 }
518
519 void BrowserViewRendererImpl::SetCompositorVisibility(bool visible) {
520 if (compositor_visible_ != visible) {
521 compositor_visible_ = visible;
522 compositor_->SetVisible(compositor_visible_);
523 }
524 }
525
526 void BrowserViewRendererImpl::ResetCompositor() {
527 compositor_.reset(content::Compositor::Create(this));
528 compositor_->SetRootLayer(scissor_clip_layer_);
529 }
530
531 void BrowserViewRendererImpl::Invalidate() {
532 if (view_visible_)
533 client_->Invalidate();
534 }
535
536 bool BrowserViewRendererImpl::RenderSW(SkCanvas* canvas) {
537 float content_scale = dpi_scale_ * page_scale_;
538 canvas->scale(content_scale, content_scale);
539
540 // Clear to white any parts of the view not covered by the scaled contents.
541 // TODO(leandrogracia): this should be automatically done by the SW rendering
542 // path once multiple layers are supported.
543 gfx::Size physical_content_size = gfx::ToCeiledSize(
544 gfx::ScaleSize(content_size_css_, content_scale));
545 if (physical_content_size.width() < view_size_.width() ||
546 physical_content_size.height() < view_size_.height())
547 canvas->clear(SK_ColorWHITE);
548
549 // TODO(leandrogracia): use the appropriate SW rendering path when available
550 // instead of abusing CapturePicture.
551 return RenderPicture(canvas);
552 }
553
554 bool BrowserViewRendererImpl::RenderPicture(SkCanvas* canvas) {
555 skia::RefPtr<SkPicture> picture = GetLastCapturedPicture();
556 if (!picture)
557 return false;
558
559 picture->draw(canvas);
560 return true;
561 }
562
563 void BrowserViewRendererImpl::OnFrameInfoUpdated(
564 const gfx::SizeF& content_size,
565 const gfx::Vector2dF& scroll_offset,
566 float page_scale_factor) {
567 page_scale_ = page_scale_factor;
568 content_size_css_ = content_size;
569 }
570
571 } // namespace android_webview
OLDNEW
« no previous file with comments | « android_webview/browser/browser_view_renderer_impl.h ('k') | android_webview/browser/in_process_view_renderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698