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

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

Issue 22035002: Android WebView: Make a custom Picture subclass (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: endRecording is OK Created 7 years, 4 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "android_webview/browser/in_process_view_renderer.h" 5 #include "android_webview/browser/in_process_view_renderer.h"
6 6
7 #include <android/bitmap.h> 7 #include <android/bitmap.h>
8 8
9 #include "android_webview/browser/aw_gl_surface.h" 9 #include "android_webview/browser/aw_gl_surface.h"
10 #include "android_webview/browser/scoped_app_gl_state_restore.h" 10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
11 #include "android_webview/common/aw_switches.h" 11 #include "android_webview/common/aw_switches.h"
12 #include "android_webview/public/browser/draw_gl.h" 12 #include "android_webview/public/browser/draw_gl.h"
13 #include "android_webview/public/browser/draw_sw.h" 13 #include "android_webview/public/browser/draw_sw.h"
14 #include "base/android/jni_android.h" 14 #include "base/android/jni_android.h"
15 #include "base/auto_reset.h" 15 #include "base/auto_reset.h"
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/debug/trace_event.h" 17 #include "base/debug/trace_event.h"
18 #include "base/lazy_instance.h" 18 #include "base/lazy_instance.h"
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
21 #include "content/public/browser/android/synchronous_compositor.h" 21 #include "content/public/browser/android/synchronous_compositor.h"
22 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h" 23 #include "content/public/browser/web_contents.h"
24 #include "gpu/command_buffer/service/in_process_command_buffer.h" 24 #include "gpu/command_buffer/service/in_process_command_buffer.h"
25 #include "skia/ext/refptr.h"
26 #include "third_party/skia/include/core/SkBitmap.h" 25 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "third_party/skia/include/core/SkCanvas.h" 26 #include "third_party/skia/include/core/SkCanvas.h"
28 #include "third_party/skia/include/core/SkDevice.h" 27 #include "third_party/skia/include/core/SkDevice.h"
29 #include "third_party/skia/include/core/SkGraphics.h" 28 #include "third_party/skia/include/core/SkGraphics.h"
30 #include "third_party/skia/include/core/SkPicture.h" 29 #include "third_party/skia/include/core/SkPicture.h"
31 #include "ui/gfx/skia_util.h" 30 #include "ui/gfx/skia_util.h"
32 #include "ui/gfx/transform.h" 31 #include "ui/gfx/transform.h"
33 #include "ui/gfx/vector2d_conversions.h" 32 #include "ui/gfx/vector2d_conversions.h"
34 #include "ui/gfx/vector2d_f.h" 33 #include "ui/gfx/vector2d_f.h"
35 34
(...skipping 21 matching lines...) Expand all
57 return NULL; 56 return NULL;
58 UserData* data = reinterpret_cast<UserData*>( 57 UserData* data = reinterpret_cast<UserData*>(
59 contents->GetUserData(kUserDataKey)); 58 contents->GetUserData(kUserDataKey));
60 return data ? data->instance_ : NULL; 59 return data ? data->instance_ : NULL;
61 } 60 }
62 61
63 private: 62 private:
64 InProcessViewRenderer* instance_; 63 InProcessViewRenderer* instance_;
65 }; 64 };
66 65
67 typedef base::Callback<bool(SkCanvas*)> RenderMethod;
68
69 bool RasterizeIntoBitmap(JNIEnv* env, 66 bool RasterizeIntoBitmap(JNIEnv* env,
70 const JavaRef<jobject>& jbitmap, 67 const JavaRef<jobject>& jbitmap,
71 int scroll_x, 68 int scroll_x,
72 int scroll_y, 69 int scroll_y,
73 const RenderMethod& renderer) { 70 const InProcessViewRenderer::RenderMethod& renderer) {
74 DCHECK(jbitmap.obj()); 71 DCHECK(jbitmap.obj());
75 72
76 AndroidBitmapInfo bitmap_info; 73 AndroidBitmapInfo bitmap_info;
77 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) { 74 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
78 LOG(ERROR) << "Error getting java bitmap info."; 75 LOG(ERROR) << "Error getting java bitmap info.";
79 return false; 76 return false;
80 } 77 }
81 78
82 void* pixels = NULL; 79 void* pixels = NULL;
83 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) { 80 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 bool HardwareEnabled() { 113 bool HardwareEnabled() {
117 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch( 114 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
118 switches::kDisableWebViewGLMode); 115 switches::kDisableWebViewGLMode);
119 return g_hw_enabled; 116 return g_hw_enabled;
120 } 117 }
121 118
122 // Provides software rendering functions from the Android glue layer. 119 // Provides software rendering functions from the Android glue layer.
123 // Allows preventing extra copies of data when rendering. 120 // Allows preventing extra copies of data when rendering.
124 AwDrawSWFunctionTable* g_sw_draw_functions = NULL; 121 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
125 122
126 // Tells if the Skia library versions in Android and Chromium are compatible.
127 // If they are then it's possible to pass Skia objects like SkPictures to the
128 // Android glue layer via the SW rendering functions.
129 // If they are not, then additional copies and rasterizations are required
130 // as a fallback mechanism, which will have an important performance impact.
131 bool g_is_skia_version_compatible = false;
132
133 const int64 kFallbackTickTimeoutInMilliseconds = 20; 123 const int64 kFallbackTickTimeoutInMilliseconds = 20;
134 124
135 class ScopedAllowGL { 125 class ScopedAllowGL {
136 public: 126 public:
137 ScopedAllowGL(); 127 ScopedAllowGL();
138 ~ScopedAllowGL(); 128 ~ScopedAllowGL();
139 129
140 static bool IsAllowed() { 130 static bool IsAllowed() {
141 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl; 131 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
142 } 132 }
(...skipping 30 matching lines...) Expand all
173 if (!renderer || !renderer->RequestProcessGL()) { 163 if (!renderer || !renderer->RequestProcessGL()) {
174 LOG(ERROR) << "Failed to request DrawGL. Probably going to deadlock."; 164 LOG(ERROR) << "Failed to request DrawGL. Probably going to deadlock.";
175 } 165 }
176 } 166 }
177 } 167 }
178 168
179 // static 169 // static
180 void BrowserViewRenderer::SetAwDrawSWFunctionTable( 170 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
181 AwDrawSWFunctionTable* table) { 171 AwDrawSWFunctionTable* table) {
182 g_sw_draw_functions = table; 172 g_sw_draw_functions = table;
183 g_is_skia_version_compatible =
184 g_sw_draw_functions->is_skia_version_compatible(&SkGraphics::GetVersion);
185 LOG_IF(WARNING, !g_is_skia_version_compatible)
186 << "Skia versions are not compatible, rendering performance will suffer.";
187
188 gpu::InProcessCommandBuffer::SetScheduleCallback( 173 gpu::InProcessCommandBuffer::SetScheduleCallback(
189 base::Bind(&ScheduleGpuWork)); 174 base::Bind(&ScheduleGpuWork));
190 } 175 }
191 176
192 // static 177 // static
193 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() { 178 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
194 return g_sw_draw_functions; 179 return g_sw_draw_functions;
195 } 180 }
196 181
197 // static
198 bool BrowserViewRenderer::IsSkiaVersionCompatible() {
199 DCHECK(g_sw_draw_functions);
200 return g_is_skia_version_compatible;
201 }
202
203 InProcessViewRenderer::InProcessViewRenderer( 182 InProcessViewRenderer::InProcessViewRenderer(
204 BrowserViewRenderer::Client* client, 183 BrowserViewRenderer::Client* client,
205 JavaHelper* java_helper, 184 JavaHelper* java_helper,
206 content::WebContents* web_contents) 185 content::WebContents* web_contents)
207 : client_(client), 186 : client_(client),
208 java_helper_(java_helper), 187 java_helper_(java_helper),
209 web_contents_(web_contents), 188 web_contents_(web_contents),
210 compositor_(NULL), 189 compositor_(NULL),
211 visible_(false), 190 visible_(false),
212 dip_scale_(0.0), 191 dip_scale_(0.0),
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect); 354 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
376 } 355 }
377 356
378 void InProcessViewRenderer::SetGlobalVisibleRect( 357 void InProcessViewRenderer::SetGlobalVisibleRect(
379 const gfx::Rect& visible_rect) { 358 const gfx::Rect& visible_rect) {
380 cached_global_visible_rect_ = visible_rect; 359 cached_global_visible_rect_ = visible_rect;
381 } 360 }
382 361
383 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas, 362 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
384 const gfx::Rect& clip) { 363 const gfx::Rect& clip) {
385 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawSW");
386 fallback_tick_.Cancel(); 364 fallback_tick_.Cancel();
387 365
388 if (clip.IsEmpty()) { 366 if (clip.IsEmpty()) {
389 TRACE_EVENT_INSTANT0( 367 TRACE_EVENT_INSTANT0(
390 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD); 368 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
391 return true; 369 return true;
392 } 370 }
393 371
394 if (!compositor_) { 372 if (!compositor_) {
395 TRACE_EVENT_INSTANT0( 373 TRACE_EVENT_INSTANT0(
396 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); 374 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
397 return false; 375 return false;
398 } 376 }
399 377
378 return RenderViaAuxilaryBitmapIfNeeded(
379 java_canvas,
380 java_helper_,
381 scroll_at_start_of_frame_,
382 clip,
383 base::Bind(&InProcessViewRenderer::CompositeSW,
384 base::Unretained(this)),
385 web_contents_);
386 }
387
388 // static
389 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
390 jobject java_canvas,
391 BrowserViewRenderer::JavaHelper* java_helper,
392 const gfx::Vector2d& scroll_correction,
393 const gfx::Rect& clip,
394 InProcessViewRenderer::RenderMethod render_source,
395 void* owner_key) {
396 TRACE_EVENT0("android_webview",
397 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
400 JNIEnv* env = AttachCurrentThread(); 398 JNIEnv* env = AttachCurrentThread();
401 399
402 AwDrawSWFunctionTable* sw_functions = GetAwDrawSWFunctionTable(); 400 AwDrawSWFunctionTable* sw_functions = GetAwDrawSWFunctionTable();
403 AwPixelInfo* pixels = sw_functions ? 401 AwPixelInfo* pixels = sw_functions ?
404 sw_functions->access_pixels(env, java_canvas) : NULL; 402 sw_functions->access_pixels(env, java_canvas) : NULL;
405 // Render into an auxiliary bitmap if pixel info is not available.
406 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
407 if (pixels == NULL) { 403 if (pixels == NULL) {
404 // Render into an auxiliary bitmap if pixel info is not available.
405 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
408 TRACE_EVENT0("android_webview", "RenderToAuxBitmap"); 406 TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
409 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap( 407 ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
410 env, clip.width(), clip.height(), jcanvas, web_contents_)); 408 env, clip.width(), clip.height(), jcanvas, owner_key));
411 if (!jbitmap.obj()) { 409 if (!jbitmap.obj()) {
412 TRACE_EVENT_INSTANT0("android_webview", 410 TRACE_EVENT_INSTANT0("android_webview",
413 "EarlyOut_BitmapAllocFail", 411 "EarlyOut_BitmapAllocFail",
414 TRACE_EVENT_SCOPE_THREAD); 412 TRACE_EVENT_SCOPE_THREAD);
415 return false; 413 return false;
416 } 414 }
417 415
418 if (!RasterizeIntoBitmap(env, jbitmap, 416 if (!RasterizeIntoBitmap(env, jbitmap,
419 clip.x() - scroll_at_start_of_frame_.x(), 417 clip.x() - scroll_correction.x(),
420 clip.y() - scroll_at_start_of_frame_.y(), 418 clip.y() - scroll_correction.y(),
421 base::Bind(&InProcessViewRenderer::CompositeSW, 419 render_source)) {
422 base::Unretained(this)))) {
423 TRACE_EVENT_INSTANT0("android_webview", 420 TRACE_EVENT_INSTANT0("android_webview",
424 "EarlyOut_RasterizeFail", 421 "EarlyOut_RasterizeFail",
425 TRACE_EVENT_SCOPE_THREAD); 422 TRACE_EVENT_SCOPE_THREAD);
426 return false; 423 return false;
427 } 424 }
428 425
429 java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas, 426 java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
430 clip.x(), clip.y()); 427 clip.x(), clip.y());
431 return true; 428 return true;
432 } 429 }
433 430
434 // Draw in a SkCanvas built over the pixel information. 431 // Draw in a SkCanvas built over the pixel information.
435 bool succeeded = false; 432 bool succeeded = false;
436 { 433 {
437 SkBitmap bitmap; 434 SkBitmap bitmap;
438 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config), 435 bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config),
439 pixels->width, 436 pixels->width,
440 pixels->height, 437 pixels->height,
441 pixels->row_bytes); 438 pixels->row_bytes);
442 bitmap.setPixels(pixels->pixels); 439 bitmap.setPixels(pixels->pixels);
443 SkDevice device(bitmap); 440 SkDevice device(bitmap);
444 SkCanvas canvas(&device); 441 SkCanvas canvas(&device);
445 SkMatrix matrix; 442 SkMatrix matrix;
446 for (int i = 0; i < 9; i++) 443 for (int i = 0; i < 9; i++)
447 matrix.set(i, pixels->matrix[i]); 444 matrix.set(i, pixels->matrix[i]);
448 canvas.setMatrix(matrix); 445 canvas.setMatrix(matrix);
449 446
450 if (pixels->clip_region_size) { 447 if (pixels->clip_region_size) {
451 SkRegion clip_region; 448 SkRegion clip_region;
452 size_t bytes_read = clip_region.readFromMemory(pixels->clip_region); 449 size_t bytes_read = clip_region.readFromMemory(pixels->clip_region);
453 DCHECK_EQ(pixels->clip_region_size, bytes_read); 450 DCHECK_EQ(pixels->clip_region_size, bytes_read);
454 canvas.setClipRegion(clip_region); 451 canvas.setClipRegion(clip_region);
455 } else { 452 } else {
456 canvas.clipRect(gfx::RectToSkRect(clip)); 453 canvas.clipRect(gfx::RectToSkRect(clip));
457 } 454 }
458 canvas.translate(scroll_at_start_of_frame_.x(), 455 canvas.translate(scroll_correction.x(),
459 scroll_at_start_of_frame_.y()); 456 scroll_correction.y());
460 457
461 succeeded = CompositeSW(&canvas); 458 succeeded = render_source.Run(&canvas);
462 } 459 }
463 460
464 sw_functions->release_pixels(pixels); 461 sw_functions->release_pixels(pixels);
465 return succeeded; 462 return succeeded;
466 } 463 }
467 464
468 base::android::ScopedJavaLocalRef<jobject> 465 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
469 InProcessViewRenderer::CapturePicture(int width, int height) { 466 int height) {
470 if (!compositor_ || !GetAwDrawSWFunctionTable()) {
471 TRACE_EVENT_INSTANT0(
472 "android_webview", "EarlyOut_CapturePicture", TRACE_EVENT_SCOPE_THREAD);
473 return ScopedJavaLocalRef<jobject>();
474 }
475
476 // Return empty Picture objects for empty SkPictures. 467 // Return empty Picture objects for empty SkPictures.
477 JNIEnv* env = AttachCurrentThread(); 468 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
478 if (width <= 0 || height <= 0) { 469 if (width <= 0 || height <= 0) {
479 return java_helper_->RecordBitmapIntoPicture(env, 470 return picture;
480 ScopedJavaLocalRef<jobject>());
481 } 471 }
482 472
483 // Reset scroll back to the origin, will go back to the old 473 // Reset scroll back to the origin, will go back to the old
484 // value when scroll_reset is out of scope. 474 // value when scroll_reset is out of scope.
485 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_css_, 475 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_css_,
486 gfx::Vector2d()); 476 gfx::Vector2d());
487 477
488 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
489 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0); 478 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
490 if (!CompositeSW(rec_canvas)) 479 if (compositor_)
491 return ScopedJavaLocalRef<jobject>(); 480 CompositeSW(rec_canvas);
492 picture->endRecording(); 481 picture->endRecording();
493 482 return picture;
494 if (IsSkiaVersionCompatible()) {
495 // Add a reference that the create_picture() will take ownership of.
496 picture->ref();
497 return ScopedJavaLocalRef<jobject>(env,
498 GetAwDrawSWFunctionTable()->create_picture(env, picture.get()));
499 }
500
501 // If Skia versions are not compatible, workaround it by rasterizing the
502 // picture into a bitmap and drawing it into a new Java picture. Pass null
503 // for |canvas| as we don't have java canvas at this point (and it would be
504 // software anyway).
505 ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap(
506 env, picture->width(), picture->height(), ScopedJavaLocalRef<jobject>(),
507 NULL));
508 if (!jbitmap.obj())
509 return ScopedJavaLocalRef<jobject>();
510
511 if (!RasterizeIntoBitmap(env, jbitmap, 0, 0,
512 base::Bind(&RenderPictureToCanvas,
513 base::Unretained(picture.get())))) {
514 return ScopedJavaLocalRef<jobject>();
515 }
516
517 return java_helper_->RecordBitmapIntoPicture(env, jbitmap);
518 } 483 }
519 484
520 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) { 485 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
521 on_new_picture_enable_ = enabled; 486 on_new_picture_enable_ = enabled;
522 } 487 }
523 488
524 void InProcessViewRenderer::OnVisibilityChanged(bool visible) { 489 void InProcessViewRenderer::OnVisibilityChanged(bool visible) {
525 TRACE_EVENT_INSTANT1("android_webview", 490 TRACE_EVENT_INSTANT1("android_webview",
526 "InProcessViewRenderer::OnVisibilityChanged", 491 "InProcessViewRenderer::OnVisibilityChanged",
527 TRACE_EVENT_SCOPE_THREAD, 492 TRACE_EVENT_SCOPE_THREAD,
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 base::StringAppendF(&str, 758 base::StringAppendF(&str,
794 "surface width height: [%d %d] ", 759 "surface width height: [%d %d] ",
795 draw_info->width, 760 draw_info->width,
796 draw_info->height); 761 draw_info->height);
797 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); 762 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
798 } 763 }
799 return str; 764 return str;
800 } 765 }
801 766
802 } // namespace android_webview 767 } // namespace android_webview
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698