OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |