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

Side by Side Diff: android_webview/browser/in_process_renderer/in_process_view_renderer.cc

Issue 15851006: Move synchronous compositor into content/browser (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/in_process_renderer/in_process_view_renderer.h "
6
7 #include <android/bitmap.h>
8
9 #include "android_webview/public/browser/draw_gl.h"
10 #include "android_webview/public/browser/draw_sw.h"
11 #include "base/android/jni_android.h"
12 #include "base/debug/trace_event.h"
13 #include "base/logging.h"
14 #include "content/public/browser/android/content_view_core.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/renderer/android/synchronous_compositor.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkDevice.h"
21 #include "third_party/skia/include/core/SkGraphics.h"
22 #include "third_party/skia/include/core/SkPicture.h"
23 #include "ui/gfx/size_conversions.h"
24 #include "ui/gfx/transform.h"
25 #include "ui/gfx/vector2d_f.h"
26 #include "ui/gl/gl_bindings.h"
27
28 // TODO(leandrogracia): Borrowed from gl2ext.h. Cannot be included due to
29 // conflicts with gl_bindings.h and the EGL library methods
30 // (eglGetCurrentContext).
31 #ifndef GL_TEXTURE_EXTERNAL_OES
32 #define GL_TEXTURE_EXTERNAL_OES 0x8D65
33 #endif
34
35 #ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
36 #define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
37 #endif
38
39 using base::android::AttachCurrentThread;
40 using base::android::JavaRef;
41 using base::android::ScopedJavaLocalRef;
42 using content::Compositor;
43 using content::ContentViewCore;
44
45 namespace android_webview {
46
47 namespace {
48
49 class GLStateRestore {
50 public:
51 GLStateRestore() {
52 #if !defined(NDEBUG)
53 {
54 GLint vertex_array_buffer_binding;
55 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding);
56 DCHECK_EQ(0, vertex_array_buffer_binding);
57
58 GLint index_array_buffer_binding;
59 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING,
60 &index_array_buffer_binding);
61 DCHECK_EQ(0, index_array_buffer_binding);
62 }
63 #endif // !defined(NDEBUG)
64 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES,
65 &texture_external_oes_binding_);
66 glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment_);
67 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment_);
68
69 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) {
70 glGetVertexAttribiv(
71 i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertex_attrib_[i].enabled);
72 glGetVertexAttribiv(
73 i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertex_attrib_[i].size);
74 glGetVertexAttribiv(
75 i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertex_attrib_[i].type);
76 glGetVertexAttribiv(
77 i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertex_attrib_[i].normalized);
78 glGetVertexAttribiv(
79 i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertex_attrib_[i].stride);
80 glGetVertexAttribPointerv(
81 i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &vertex_attrib_[i].pointer);
82 }
83
84 glGetBooleanv(GL_DEPTH_TEST, &depth_test_);
85 glGetBooleanv(GL_CULL_FACE, &cull_face_);
86 glGetBooleanv(GL_COLOR_WRITEMASK, color_mask_);
87 glGetBooleanv(GL_BLEND, &blend_enabled_);
88 glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb_);
89 glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha_);
90 glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb_);
91 glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha_);
92 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_);
93 glGetIntegerv(GL_VIEWPORT, viewport_);
94 glGetBooleanv(GL_SCISSOR_TEST, &scissor_test_);
95 glGetIntegerv(GL_SCISSOR_BOX, scissor_box_);
96 glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_);
97 }
98
99 ~GLStateRestore() {
100 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding_);
101 glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment_);
102 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_);
103
104 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) {
105 glVertexAttribPointer(i,
106 vertex_attrib_[i].size,
107 vertex_attrib_[i].type,
108 vertex_attrib_[i].normalized,
109 vertex_attrib_[i].stride,
110 vertex_attrib_[i].pointer);
111
112 if (vertex_attrib_[i].enabled) {
113 glEnableVertexAttribArray(i);
114 } else {
115 glDisableVertexAttribArray(i);
116 }
117 }
118
119 if (depth_test_) {
120 glEnable(GL_DEPTH_TEST);
121 } else {
122 glDisable(GL_DEPTH_TEST);
123 }
124
125 if (cull_face_) {
126 glEnable(GL_CULL_FACE);
127 } else {
128 glDisable(GL_CULL_FACE);
129 }
130
131 glColorMask(color_mask_[0], color_mask_[1], color_mask_[2], color_mask_[3]);
132
133 if (blend_enabled_) {
134 glEnable(GL_BLEND);
135 } else {
136 glDisable(GL_BLEND);
137 }
138
139 glBlendFuncSeparate(
140 blend_src_rgb_, blend_dest_rgb_, blend_src_alpha_, blend_dest_alpha_);
141 glActiveTexture(active_texture_);
142
143 glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
144
145 if (scissor_test_) {
146 glEnable(GL_SCISSOR_TEST);
147 } else {
148 glDisable(GL_SCISSOR_TEST);
149 }
150
151 glScissor(
152 scissor_box_[0], scissor_box_[1], scissor_box_[2], scissor_box_[3]);
153
154 glUseProgram(current_program_);
155
156 glBindBuffer(GL_ARRAY_BUFFER, 0);
157 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
158 }
159
160 private:
161 GLint texture_external_oes_binding_;
162 GLint pack_alignment_;
163 GLint unpack_alignment_;
164
165 struct {
166 GLint enabled;
167 GLint size;
168 GLint type;
169 GLint normalized;
170 GLint stride;
171 GLvoid* pointer;
172 } vertex_attrib_[3];
173
174 GLboolean depth_test_;
175 GLboolean cull_face_;
176 GLboolean color_mask_[4];
177 GLboolean blend_enabled_;
178 GLint blend_src_rgb_;
179 GLint blend_src_alpha_;
180 GLint blend_dest_rgb_;
181 GLint blend_dest_alpha_;
182 GLint active_texture_;
183 GLint viewport_[4];
184 GLboolean scissor_test_;
185 GLint scissor_box_[4];
186 GLint current_program_;
187 };
188
189 const void* kUserDataKey = &kUserDataKey;
190
191 class UserData : public content::WebContents::Data {
192 public:
193 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
194 virtual ~UserData() {
195 instance_->WebContentsGone();
196 }
197
198 static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
199 if (!contents)
200 return NULL;
201 UserData* data = reinterpret_cast<UserData*>(
202 contents->GetUserData(kUserDataKey));
203 return data ? data->instance_ : NULL;
204 }
205
206 private:
207 InProcessViewRenderer* instance_;
208 };
209
210 typedef base::Callback<bool(SkCanvas*)> RenderMethod;
211
212 bool RasterizeIntoBitmap(JNIEnv* env,
213 const JavaRef<jobject>& jbitmap,
214 int scroll_x,
215 int scroll_y,
216 const RenderMethod& renderer) {
217 DCHECK(jbitmap.obj());
218
219 AndroidBitmapInfo bitmap_info;
220 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
221 LOG(ERROR) << "Error getting java bitmap info.";
222 return false;
223 }
224
225 void* pixels = NULL;
226 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
227 LOG(ERROR) << "Error locking java bitmap pixels.";
228 return false;
229 }
230
231 bool succeeded;
232 {
233 SkBitmap bitmap;
234 bitmap.setConfig(SkBitmap::kARGB_8888_Config,
235 bitmap_info.width,
236 bitmap_info.height,
237 bitmap_info.stride);
238 bitmap.setPixels(pixels);
239
240 SkDevice device(bitmap);
241 SkCanvas canvas(&device);
242 canvas.translate(-scroll_x, -scroll_y);
243 succeeded = renderer.Run(&canvas);
244 }
245
246 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
247 LOG(ERROR) << "Error unlocking java bitmap pixels.";
248 return false;
249 }
250
251 return succeeded;
252 }
253
254 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
255 canvas->drawPicture(*picture);
256 return true;
257 }
258
259 } // namespace
260
261 InProcessViewRenderer::InProcessViewRenderer(
262 BrowserViewRenderer::Client* client,
263 JavaHelper* java_helper)
264 : client_(client),
265 java_helper_(java_helper),
266 web_contents_(NULL),
267 compositor_(NULL),
268 view_visible_(false),
269 continuous_invalidate_(false),
270 continuous_invalidate_task_pending_(false),
271 width_(0),
272 height_(0),
273 attached_to_window_(false),
274 hardware_initialized_(false),
275 hardware_failed_(false),
276 egl_context_at_init_(NULL),
277 weak_factory_(this) {
278 }
279
280 InProcessViewRenderer::~InProcessViewRenderer() {
281 if (compositor_)
282 compositor_->SetClient(NULL);
283 SetContents(NULL);
284 }
285
286 // static
287 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
288 content::WebContents* contents) {
289 return UserData::GetInstance(contents);
290 }
291
292 // static
293 InProcessViewRenderer* InProcessViewRenderer::FromId(int render_process_id,
294 int render_view_id) {
295 const content::RenderViewHost* rvh =
296 content::RenderViewHost::FromID(render_process_id, render_view_id);
297 if (!rvh) return NULL;
298 return InProcessViewRenderer::FromWebContents(
299 content::WebContents::FromRenderViewHost(rvh));
300 }
301
302 void InProcessViewRenderer::BindSynchronousCompositor(
303 content::SynchronousCompositor* compositor) {
304 DCHECK(compositor && compositor_ != compositor);
305 if (compositor_)
306 compositor_->SetClient(NULL);
307 compositor_ = compositor;
308 hardware_initialized_ = false;
309 hardware_failed_ = false;
310 compositor_->SetClient(this);
311
312 if (attached_to_window_)
313 client_->RequestProcessMode();
314 }
315
316 void InProcessViewRenderer::SetContents(
317 content::ContentViewCore* content_view_core) {
318 // First remove association from the prior ContentViewCore / WebContents.
319 if (web_contents_) {
320 web_contents_->SetUserData(kUserDataKey, NULL);
321 DCHECK(!web_contents_); // WebContentsGone should have been called.
322 }
323
324 if (!content_view_core)
325 return;
326
327 web_contents_ = content_view_core->GetWebContents();
328 web_contents_->SetUserData(kUserDataKey, new UserData(this));
329 }
330
331 void InProcessViewRenderer::WebContentsGone() {
332 web_contents_ = NULL;
333 }
334
335 bool InProcessViewRenderer::PrepareDrawGL(int x, int y) {
336 // No harm in updating |hw_rendering_scroll_| even if we return false.
337 hw_rendering_scroll_ = gfx::Point(x, y);
338 return attached_to_window_ && compositor_ && compositor_->IsHwReady() &&
339 !hardware_failed_;
340 }
341
342 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
343 DCHECK(view_visible_);
344
345 // We need to watch if the current Android context has changed and enforce
346 // a clean-up in the compositor.
347 EGLContext current_context = eglGetCurrentContext();
348 if (!current_context) {
349 LOG(WARNING) << "No current context attached. Skipping composite.";
350 return;
351 }
352
353 GLStateRestore state_restore;
354
355 if (attached_to_window_ && compositor_ && !hardware_initialized_) {
356 // TODO(boliu): Actually initialize the compositor GL path.
357 hardware_initialized_ = true;
358 egl_context_at_init_ = current_context;
359 }
360
361 if (draw_info->mode == AwDrawGLInfo::kModeProcess)
362 return;
363
364 if (egl_context_at_init_ != current_context) {
365 // TODO(boliu): Handle context lost
366 }
367
368 // TODO(boliu): Make sure this is not called before compositor is initialized
369 // and GL is ready. Then make this a DCHECK.
370 if (!compositor_)
371 return;
372
373 gfx::Transform transform;
374 transform.matrix().setColMajorf(draw_info->transform);
375 transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y());
376 // TODO(joth): Check return value.
377 compositor_->DemandDrawHw(
378 gfx::Size(draw_info->width, draw_info->height),
379 transform,
380 gfx::Rect(draw_info->clip_left,
381 draw_info->clip_top,
382 draw_info->clip_right - draw_info->clip_left,
383 draw_info->clip_bottom - draw_info->clip_top));
384
385 EnsureContinuousInvalidation();
386 }
387
388 bool InProcessViewRenderer::DrawSW(jobject java_canvas,
389 const gfx::Rect& clip) {
390 bool result = DrawSWInternal(java_canvas, clip);
391 EnsureContinuousInvalidation();
392 return result;
393 }
394
395 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
396 const gfx::Rect& clip) {
397 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawSW");
398
399 if (clip.IsEmpty()) {
400 TRACE_EVENT_INSTANT0("android_webview", "Empty Clip",
401 TRACE_EVENT_SCOPE_THREAD);
402 return true;
403 }
404
405 JNIEnv* env = AttachCurrentThread();
406
407 AwDrawSWFunctionTable* sw_functions = GetAwDrawSWFunctionTable();
408 AwPixelInfo* pixels = sw_functions ?
409 sw_functions->access_pixels(env, java_canvas) : NULL;
410 // Render into an auxiliary bitmap if pixel info is not available.
411 if (pixels == NULL) {
412 TRACE_EVENT0("android_webview", "Render to Aux Bitmap");
413 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
414 env, clip.width(), clip.height(), true));
415 if (!jbitmap.obj()) {
416 TRACE_EVENT_INSTANT0("android_webview", "Bitmap Alloc Fail",
417 TRACE_EVENT_SCOPE_THREAD);
418 return false;
419 }
420
421 if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(),
422 base::Bind(&InProcessViewRenderer::RenderSW,
423 base::Unretained(this)))) {
424 TRACE_EVENT_INSTANT0("android_webview", "Rasterize Fail",
425 TRACE_EVENT_SCOPE_THREAD);
426 return false;
427 }
428
429 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
430 java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas);
431 return true;
432 }
433
434 // Draw in a SkCanvas built over the pixel information.
435 bool succeeded = false;
436 {
437 SkBitmap bitmap;
438 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
439 pixels->width,
440 pixels->height,
441 pixels->row_bytes);
442 bitmap.setPixels(pixels->pixels);
443 SkDevice device(bitmap);
444 SkCanvas canvas(&device);
445 SkMatrix matrix;
446 for (int i = 0; i < 9; i++)
447 matrix.set(i, pixels->matrix[i]);
448 canvas.setMatrix(matrix);
449
450 SkRegion clip;
451 if (pixels->clip_region_size) {
452 size_t bytes_read = clip.readFromMemory(pixels->clip_region);
453 DCHECK_EQ(pixels->clip_region_size, bytes_read);
454 canvas.setClipRegion(clip);
455 } else {
456 clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height));
457 }
458
459 succeeded = RenderSW(&canvas);
460 }
461
462 sw_functions->release_pixels(pixels);
463 return succeeded;
464 }
465
466 base::android::ScopedJavaLocalRef<jobject>
467 InProcessViewRenderer::CapturePicture() {
468 if (!GetAwDrawSWFunctionTable())
469 return ScopedJavaLocalRef<jobject>();
470
471 gfx::Size record_size(width_, height_);
472
473 // Return empty Picture objects for empty SkPictures.
474 JNIEnv* env = AttachCurrentThread();
475 if (record_size.width() <= 0 || record_size.height() <= 0) {
476 return java_helper_->RecordBitmapIntoPicture(
477 env, ScopedJavaLocalRef<jobject>());
478 }
479
480 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
481 SkCanvas* rec_canvas = picture->beginRecording(record_size.width(),
482 record_size.height(),
483 0);
484 if (!CompositeSW(rec_canvas))
485 return ScopedJavaLocalRef<jobject>();
486 picture->endRecording();
487
488 if (IsSkiaVersionCompatible()) {
489 // Add a reference that the create_picture() will take ownership of.
490 picture->ref();
491 return ScopedJavaLocalRef<jobject>(env,
492 GetAwDrawSWFunctionTable()->create_picture(env, picture.get()));
493 }
494
495 // If Skia versions are not compatible, workaround it by rasterizing the
496 // picture into a bitmap and drawing it into a new Java picture. Pass false
497 // for |cache_result| as the picture we create will hold a shallow reference
498 // to the bitmap drawn, and we don't want subsequent draws to corrupt any
499 // previously returned pictures.
500 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
501 env, picture->width(), picture->height(), false));
502 if (!jbitmap.obj())
503 return ScopedJavaLocalRef<jobject>();
504
505 if (!RasterizeIntoBitmap(env, jbitmap, 0, 0,
506 base::Bind(&RenderPictureToCanvas,
507 base::Unretained(picture.get())))) {
508 return ScopedJavaLocalRef<jobject>();
509 }
510
511 return java_helper_->RecordBitmapIntoPicture(env, jbitmap);
512 }
513
514 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
515 }
516
517 void InProcessViewRenderer::OnVisibilityChanged(bool view_visible,
518 bool window_visible) {
519 view_visible_ = window_visible && view_visible;
520 }
521
522 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
523 width_ = width;
524 height_ = height;
525 }
526
527 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
528 attached_to_window_ = true;
529 width_ = width;
530 height_ = height;
531 if (compositor_ && !hardware_initialized_)
532 client_->RequestProcessMode();
533 }
534
535 void InProcessViewRenderer::OnDetachedFromWindow() {
536 // TODO(joth): Release GL resources. crbug.com/231986.
537 attached_to_window_ = false;
538 }
539
540 bool InProcessViewRenderer::IsAttachedToWindow() {
541 return attached_to_window_;
542 }
543
544 bool InProcessViewRenderer::IsViewVisible() {
545 return view_visible_;
546 }
547
548 gfx::Rect InProcessViewRenderer::GetScreenRect() {
549 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
550 }
551
552 void InProcessViewRenderer::DidDestroyCompositor(
553 content::SynchronousCompositor* compositor) {
554 // Allow for transient hand-over when two compositors may reference
555 // a single client.
556 if (compositor_ == compositor)
557 compositor_ = NULL;
558 }
559
560 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
561 if (continuous_invalidate_ == invalidate)
562 return;
563
564 continuous_invalidate_ = invalidate;
565 // TODO(boliu): Handle if not attached to window case.
566 EnsureContinuousInvalidation();
567 }
568
569 void InProcessViewRenderer::Invalidate() {
570 continuous_invalidate_task_pending_ = false;
571 if (continuous_invalidate_)
572 client_->Invalidate();
573 }
574
575 void InProcessViewRenderer::EnsureContinuousInvalidation() {
576 if (continuous_invalidate_ && !continuous_invalidate_task_pending_) {
577 base::MessageLoop::current()->PostTask(FROM_HERE,
578 base::Bind(&InProcessViewRenderer::Invalidate,
579 weak_factory_.GetWeakPtr()));
580 continuous_invalidate_task_pending_ = true;
581 }
582 }
583
584 bool InProcessViewRenderer::RenderSW(SkCanvas* canvas) {
585 // TODO(joth): BrowserViewRendererImpl had a bunch of logic for dpi and page
586 // scale here. Determine what if any needs bringing over to this class.
587 return CompositeSW(canvas);
588 }
589
590 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
591 return compositor_ && compositor_->DemandDrawSw(canvas);
592 }
593
594 } // namespace android_webview
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698