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 3 // found in the LICENSE file. 4 5 #include "android_webview/browser/in_process_view_renderer.h" 6 7 #include <android/bitmap.h> 8 9 #include "android_webview/browser/aw_gl_surface.h" 10 #include "android_webview/browser/scoped_app_gl_state_restore.h" 11 #include "android_webview/common/aw_switches.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/auto_reset.h" 16 #include "base/command_line.h" 17 #include "base/debug/trace_event.h" 18 #include "base/lazy_instance.h" 19 #include "base/logging.h" 20 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/stringprintf.h" 22 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/web_contents.h" 24 #include "content/public/common/content_switches.h" 25 #include "gpu/command_buffer/service/in_process_command_buffer.h" 26 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "third_party/skia/include/core/SkBitmapDevice.h" 28 #include "third_party/skia/include/core/SkCanvas.h" 29 #include "third_party/skia/include/core/SkGraphics.h" 30 #include "third_party/skia/include/core/SkPicture.h" 31 #include "third_party/skia/include/utils/SkCanvasStateUtils.h" 32 #include "ui/gfx/skia_util.h" 33 #include "ui/gfx/transform.h" 34 #include "ui/gfx/vector2d_conversions.h" 35 #include "ui/gfx/vector2d_f.h" 36 37 using base::android::AttachCurrentThread; 38 using base::android::JavaRef; 39 using base::android::ScopedJavaLocalRef; 40 using content::BrowserThread; 41 42 namespace android_webview { 43 44 namespace { 45 46 47 const void* kUserDataKey = &kUserDataKey; 48 49 class UserData : public content::WebContents::Data { 50 public: 51 UserData(InProcessViewRenderer* ptr) : instance_(ptr) {} 52 virtual ~UserData() { 53 instance_->WebContentsGone(); 54 } 55 56 static InProcessViewRenderer* GetInstance(content::WebContents* contents) { 57 if (!contents) 58 return NULL; 59 UserData* data = reinterpret_cast<UserData*>( 60 contents->GetUserData(kUserDataKey)); 61 return data ? data->instance_ : NULL; 62 } 63 64 private: 65 InProcessViewRenderer* instance_; 66 }; 67 68 bool RasterizeIntoBitmap(JNIEnv* env, 69 const JavaRef<jobject>& jbitmap, 70 int scroll_x, 71 int scroll_y, 72 const InProcessViewRenderer::RenderMethod& renderer) { 73 DCHECK(jbitmap.obj()); 74 75 AndroidBitmapInfo bitmap_info; 76 if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) { 77 LOG(ERROR) << "Error getting java bitmap info."; 78 return false; 79 } 80 81 void* pixels = NULL; 82 if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) { 83 LOG(ERROR) << "Error locking java bitmap pixels."; 84 return false; 85 } 86 87 bool succeeded; 88 { 89 SkBitmap bitmap; 90 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 91 bitmap_info.width, 92 bitmap_info.height, 93 bitmap_info.stride); 94 bitmap.setPixels(pixels); 95 96 SkBitmapDevice device(bitmap); 97 SkCanvas canvas(&device); 98 canvas.translate(-scroll_x, -scroll_y); 99 succeeded = renderer.Run(&canvas); 100 } 101 102 if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) { 103 LOG(ERROR) << "Error unlocking java bitmap pixels."; 104 return false; 105 } 106 107 return succeeded; 108 } 109 110 class ScopedPixelAccess { 111 public: 112 ScopedPixelAccess(JNIEnv* env, jobject java_canvas) { 113 AwDrawSWFunctionTable* sw_functions = 114 BrowserViewRenderer::GetAwDrawSWFunctionTable(); 115 pixels_ = sw_functions ? 116 sw_functions->access_pixels(env, java_canvas) : NULL; 117 } 118 ~ScopedPixelAccess() { 119 if (pixels_) 120 BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_); 121 } 122 AwPixelInfo* pixels() { return pixels_; } 123 124 private: 125 AwPixelInfo* pixels_; 126 127 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess); 128 }; 129 130 bool HardwareEnabled() { 131 static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch( 132 switches::kDisableWebViewGLMode); 133 return g_hw_enabled; 134 } 135 136 // Provides software rendering functions from the Android glue layer. 137 // Allows preventing extra copies of data when rendering. 138 AwDrawSWFunctionTable* g_sw_draw_functions = NULL; 139 140 const int64 kFallbackTickTimeoutInMilliseconds = 20; 141 142 143 // Used to calculate memory and resource allocation. Determined experimentally. 144 size_t g_memory_multiplier = 10; 145 size_t g_num_gralloc_limit = 150; 146 const size_t kBytesPerPixel = 4; 147 const size_t kMemoryAllocationStep = 5 * 1024 * 1024; 148 149 class ScopedAllowGL { 150 public: 151 ScopedAllowGL(); 152 ~ScopedAllowGL(); 153 154 static bool IsAllowed() { 155 return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl; 156 } 157 158 private: 159 static bool allow_gl; 160 161 DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL); 162 }; 163 164 ScopedAllowGL::ScopedAllowGL() { 165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 166 DCHECK(!allow_gl); 167 allow_gl = true; 168 } 169 170 ScopedAllowGL::~ScopedAllowGL() { 171 allow_gl = false; 172 } 173 174 bool ScopedAllowGL::allow_gl = false; 175 176 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager = 177 LAZY_INSTANCE_INITIALIZER; 178 179 void RequestProcessGLOnUIThread() { 180 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 181 BrowserThread::PostTask( 182 BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread)); 183 return; 184 } 185 186 InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>( 187 g_view_renderer_manager.Get().GetMostRecentlyDrawn()); 188 if (!renderer || !renderer->RequestProcessGL()) { 189 LOG(ERROR) << "Failed to request GL process. Deadlock likely: " 190 << !!renderer; 191 } 192 } 193 194 class DeferredGpuCommandService 195 : public gpu::InProcessCommandBuffer::Service, 196 public base::RefCountedThreadSafe<DeferredGpuCommandService> { 197 public: 198 DeferredGpuCommandService(); 199 200 virtual void ScheduleTask(const base::Closure& task) OVERRIDE; 201 virtual void ScheduleIdleWork(const base::Closure& task) OVERRIDE; 202 virtual bool UseVirtualizedGLContexts() OVERRIDE; 203 204 void RunTasks(); 205 206 virtual void AddRef() const OVERRIDE { 207 base::RefCountedThreadSafe<DeferredGpuCommandService>::AddRef(); 208 } 209 virtual void Release() const OVERRIDE { 210 base::RefCountedThreadSafe<DeferredGpuCommandService>::Release(); 211 } 212 213 protected: 214 virtual ~DeferredGpuCommandService(); 215 friend class base::RefCountedThreadSafe<DeferredGpuCommandService>; 216 217 private: 218 base::Lock tasks_lock_; 219 std::queue<base::Closure> tasks_; 220 DISALLOW_COPY_AND_ASSIGN(DeferredGpuCommandService); 221 }; 222 223 DeferredGpuCommandService::DeferredGpuCommandService() {} 224 225 DeferredGpuCommandService::~DeferredGpuCommandService() { 226 base::AutoLock lock(tasks_lock_); 227 DCHECK(tasks_.empty()); 228 } 229 230 // Called from different threads! 231 void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) { 232 { 233 base::AutoLock lock(tasks_lock_); 234 tasks_.push(task); 235 } 236 if (ScopedAllowGL::IsAllowed()) { 237 RunTasks(); 238 } else { 239 RequestProcessGLOnUIThread(); 240 } 241 } 242 243 void DeferredGpuCommandService::ScheduleIdleWork( 244 const base::Closure& callback) { 245 // TODO(sievers): Should this do anything? 246 } 247 248 bool DeferredGpuCommandService::UseVirtualizedGLContexts() { return true; } 249 250 void DeferredGpuCommandService::RunTasks() { 251 bool has_more_tasks; 252 { 253 base::AutoLock lock(tasks_lock_); 254 has_more_tasks = tasks_.size() > 0; 255 } 256 257 while (has_more_tasks) { 258 base::Closure task; 259 { 260 base::AutoLock lock(tasks_lock_); 261 task = tasks_.front(); 262 tasks_.pop(); 263 } 264 task.Run(); 265 { 266 base::AutoLock lock(tasks_lock_); 267 has_more_tasks = tasks_.size() > 0; 268 } 269 270 } 271 } 272 273 base::LazyInstance<scoped_refptr<DeferredGpuCommandService> > g_service = 274 LAZY_INSTANCE_INITIALIZER; 275 276 } // namespace 277 278 // static 279 void BrowserViewRenderer::SetAwDrawSWFunctionTable( 280 AwDrawSWFunctionTable* table) { 281 g_sw_draw_functions = table; 282 } 283 284 // static 285 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() { 286 return g_sw_draw_functions; 287 } 288 289 InProcessViewRenderer::InProcessViewRenderer( 290 BrowserViewRenderer::Client* client, 291 JavaHelper* java_helper, 292 content::WebContents* web_contents) 293 : client_(client), 294 java_helper_(java_helper), 295 web_contents_(web_contents), 296 compositor_(NULL), 297 is_paused_(false), 298 view_visible_(false), 299 window_visible_(false), 300 attached_to_window_(false), 301 dip_scale_(0.0), 302 page_scale_factor_(1.0), 303 on_new_picture_enable_(false), 304 compositor_needs_continuous_invalidate_(false), 305 block_invalidates_(false), 306 width_(0), 307 height_(0), 308 hardware_initialized_(false), 309 hardware_failed_(false), 310 last_egl_context_(NULL), 311 manager_key_(g_view_renderer_manager.Get().NullKey()) { 312 CHECK(web_contents_); 313 web_contents_->SetUserData(kUserDataKey, new UserData(this)); 314 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this); 315 316 // Currently the logic in this class relies on |compositor_| remaining NULL 317 // until the DidInitializeCompositor() call, hence it is not set here. 318 } 319 320 InProcessViewRenderer::~InProcessViewRenderer() { 321 CHECK(web_contents_); 322 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL); 323 web_contents_->SetUserData(kUserDataKey, NULL); 324 NoLongerExpectsDrawGL(); 325 DCHECK(web_contents_ == NULL); // WebContentsGone should have been called. 326 } 327 328 void InProcessViewRenderer::NoLongerExpectsDrawGL() { 329 GLViewRendererManager& mru = g_view_renderer_manager.Get(); 330 if (manager_key_ != mru.NullKey()) { 331 mru.NoLongerExpectsDrawGL(manager_key_); 332 manager_key_ = mru.NullKey(); 333 } 334 } 335 336 // static 337 InProcessViewRenderer* InProcessViewRenderer::FromWebContents( 338 content::WebContents* contents) { 339 return UserData::GetInstance(contents); 340 } 341 342 void InProcessViewRenderer::WebContentsGone() { 343 web_contents_ = NULL; 344 compositor_ = NULL; 345 } 346 347 // static 348 void InProcessViewRenderer::CalculateTileMemoryPolicy() { 349 CommandLine* cl = CommandLine::ForCurrentProcess(); 350 if (cl->HasSwitch(switches::kTileMemoryMultiplier)) { 351 std::string string_value = 352 cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier); 353 int int_value = 0; 354 if (base::StringToInt(string_value, &int_value) && 355 int_value >= 2 && int_value <= 50) { 356 g_memory_multiplier = int_value; 357 } 358 } 359 360 if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) { 361 std::string string_value = 362 cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview); 363 int int_value = 0; 364 if (base::StringToInt(string_value, &int_value) && 365 int_value >= 50 && int_value <= 500) { 366 g_num_gralloc_limit = int_value; 367 } 368 } 369 370 const char kDefaultTileSize[] = "384"; 371 if (!cl->HasSwitch(switches::kDefaultTileWidth)) 372 cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize); 373 374 if (!cl->HasSwitch(switches::kDefaultTileHeight)) 375 cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize); 376 } 377 378 bool InProcessViewRenderer::RequestProcessGL() { 379 return client_->RequestDrawGL(NULL); 380 } 381 382 void InProcessViewRenderer::TrimMemory(int level) { 383 // Constants from Android ComponentCallbacks2. 384 enum { 385 TRIM_MEMORY_RUNNING_LOW = 10, 386 TRIM_MEMORY_UI_HIDDEN = 20, 387 TRIM_MEMORY_BACKGROUND = 40, 388 }; 389 390 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because 391 // it does not indicate memory pressure, but merely that the app is 392 // backgrounded. 393 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN) 394 return; 395 396 // Nothing to drop. 397 if (!attached_to_window_ || !hardware_initialized_ || !compositor_) 398 return; 399 400 // Do not release resources on view we expect to get DrawGL soon. 401 if (level < TRIM_MEMORY_BACKGROUND) { 402 client_->UpdateGlobalVisibleRect(); 403 if (view_visible_ && window_visible_ && 404 !cached_global_visible_rect_.IsEmpty()) { 405 return; 406 } 407 } 408 409 if (!eglGetCurrentContext()) { 410 NOTREACHED(); 411 return; 412 } 413 414 // Just set the memory limit to 0 and drop all tiles. This will be reset to 415 // normal levels in the next DrawGL call. 416 content::SynchronousCompositorMemoryPolicy policy; 417 policy.bytes_limit = 0; 418 policy.num_resources_limit = 0; 419 if (memory_policy_ == policy) 420 return; 421 422 TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory"); 423 ScopedAppGLStateRestore state_restore( 424 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT); 425 g_service.Get()->RunTasks(); 426 ScopedAllowGL allow_gl; 427 428 SetMemoryPolicy(policy); 429 ForceFakeCompositeSW(); 430 } 431 432 void InProcessViewRenderer::SetMemoryPolicy( 433 content::SynchronousCompositorMemoryPolicy& new_policy) { 434 if (memory_policy_ == new_policy) 435 return; 436 437 memory_policy_ = new_policy; 438 compositor_->SetMemoryPolicy(memory_policy_); 439 } 440 441 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() { 442 client_->UpdateGlobalVisibleRect(); 443 } 444 445 bool InProcessViewRenderer::OnDraw(jobject java_canvas, 446 bool is_hardware_canvas, 447 const gfx::Vector2d& scroll, 448 const gfx::Rect& clip) { 449 scroll_at_start_of_frame_ = scroll; 450 if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) { 451 // We should be performing a hardware draw here. If we don't have the 452 // comositor yet or if RequestDrawGL fails, it means we failed this draw and 453 // thus return false here to clear to background color for this draw. 454 return compositor_ && client_->RequestDrawGL(java_canvas); 455 } 456 // Perform a software draw 457 return DrawSWInternal(java_canvas, clip); 458 } 459 460 bool InProcessViewRenderer::InitializeHwDraw() { 461 TRACE_EVENT0("android_webview", "InitializeHwDraw"); 462 DCHECK(!gl_surface_); 463 gl_surface_ = new AwGLSurface; 464 if (!g_service.Get()) { 465 g_service.Get() = new DeferredGpuCommandService; 466 content::SynchronousCompositor::SetGpuService(g_service.Get()); 467 } 468 hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_); 469 hardware_initialized_ = true; 470 471 if (hardware_failed_) 472 gl_surface_ = NULL; 473 474 return !hardware_failed_; 475 } 476 477 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) { 478 TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL"); 479 480 manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this); 481 482 // We need to watch if the current Android context has changed and enforce 483 // a clean-up in the compositor. 484 EGLContext current_context = eglGetCurrentContext(); 485 if (!current_context) { 486 TRACE_EVENT_INSTANT0( 487 "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD); 488 return; 489 } 490 491 ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW); 492 if (g_service.Get()) 493 g_service.Get()->RunTasks(); 494 ScopedAllowGL allow_gl; 495 496 if (!attached_to_window_) { 497 TRACE_EVENT_INSTANT0( 498 "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD); 499 return; 500 } 501 502 if (draw_info->mode == AwDrawGLInfo::kModeProcess) { 503 TRACE_EVENT_INSTANT0( 504 "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD); 505 return; 506 } 507 508 if (compositor_ && !hardware_initialized_) { 509 if (InitializeHwDraw()) { 510 last_egl_context_ = current_context; 511 } else { 512 TRACE_EVENT_INSTANT0( 513 "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD); 514 LOG(ERROR) << "WebView hardware initialization failed"; 515 return; 516 } 517 } 518 519 UpdateCachedGlobalVisibleRect(); 520 if (cached_global_visible_rect_.IsEmpty()) { 521 TRACE_EVENT_INSTANT0("android_webview", 522 "EarlyOut_EmptyVisibleRect", 523 TRACE_EVENT_SCOPE_THREAD); 524 return; 525 } 526 527 if (last_egl_context_ != current_context) { 528 // TODO(boliu): Handle context lost 529 TRACE_EVENT_INSTANT0( 530 "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD); 531 } 532 533 if (!compositor_) { 534 TRACE_EVENT_INSTANT0( 535 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); 536 return; 537 } 538 539 // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as 540 // well just to be safe. 541 fallback_tick_.Cancel(); 542 543 // Update memory budget. This will no-op in compositor if the policy has not 544 // changed since last draw. 545 content::SynchronousCompositorMemoryPolicy policy; 546 policy.bytes_limit = g_memory_multiplier * kBytesPerPixel * 547 cached_global_visible_rect_.width() * 548 cached_global_visible_rect_.height(); 549 // Round up to a multiple of kMemoryAllocationStep. 550 policy.bytes_limit = 551 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep; 552 policy.num_resources_limit = g_num_gralloc_limit; 553 SetMemoryPolicy(policy); 554 555 DCHECK(gl_surface_); 556 gl_surface_->SetBackingFrameBufferObject( 557 state_restore.framebuffer_binding_ext()); 558 559 gfx::Transform transform; 560 transform.matrix().setColMajorf(draw_info->transform); 561 transform.Translate(scroll_at_start_of_frame_.x(), 562 scroll_at_start_of_frame_.y()); 563 gfx::Rect clip_rect(draw_info->clip_left, 564 draw_info->clip_top, 565 draw_info->clip_right - draw_info->clip_left, 566 draw_info->clip_bottom - draw_info->clip_top); 567 568 // Assume we always draw the full visible rect if we are drawing into a layer. 569 bool drew_full_visible_rect = true; 570 571 gfx::Rect viewport_rect; 572 if (!draw_info->is_layer) { 573 viewport_rect = cached_global_visible_rect_; 574 clip_rect.Intersect(viewport_rect); 575 drew_full_visible_rect = clip_rect.Contains(viewport_rect); 576 } else { 577 viewport_rect = clip_rect; 578 } 579 580 block_invalidates_ = true; 581 // TODO(joth): Check return value. 582 compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height), 583 transform, 584 viewport_rect, 585 clip_rect, 586 state_restore.stencil_enabled()); 587 block_invalidates_ = false; 588 gl_surface_->ResetBackingFrameBufferObject(); 589 590 EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect); 591 } 592 593 void InProcessViewRenderer::SetGlobalVisibleRect( 594 const gfx::Rect& visible_rect) { 595 cached_global_visible_rect_ = visible_rect; 596 } 597 598 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas, 599 const gfx::Rect& clip) { 600 if (clip.IsEmpty()) { 601 TRACE_EVENT_INSTANT0( 602 "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD); 603 return true; 604 } 605 606 if (!compositor_) { 607 TRACE_EVENT_INSTANT0( 608 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); 609 return false; 610 } 611 612 return RenderViaAuxilaryBitmapIfNeeded( 613 java_canvas, 614 java_helper_, 615 scroll_at_start_of_frame_, 616 clip, 617 base::Bind(&InProcessViewRenderer::CompositeSW, 618 base::Unretained(this)), 619 web_contents_); 620 } 621 622 // static 623 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded( 624 jobject java_canvas, 625 BrowserViewRenderer::JavaHelper* java_helper, 626 const gfx::Vector2d& scroll_correction, 627 const gfx::Rect& clip, 628 InProcessViewRenderer::RenderMethod render_source, 629 void* owner_key) { 630 TRACE_EVENT0("android_webview", 631 "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded"); 632 633 JNIEnv* env = AttachCurrentThread(); 634 ScopedPixelAccess auto_release_pixels(env, java_canvas); 635 AwPixelInfo* pixels = auto_release_pixels.pixels(); 636 if (pixels && pixels->state) { 637 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef( 638 SkCanvasStateUtils::CreateFromCanvasState(pixels->state)); 639 640 // Workarounds for http://crbug.com/271096: SW draw only supports 641 // translate & scale transforms, and a simple rectangular clip. 642 if (canvas && (!canvas->getTotalClip().isRect() || 643 (canvas->getTotalMatrix().getType() & 644 ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) { 645 canvas.clear(); 646 } 647 if (canvas) { 648 canvas->translate(scroll_correction.x(), scroll_correction.y()); 649 return render_source.Run(canvas.get()); 650 } 651 } 652 653 // Render into an auxiliary bitmap if pixel info is not available. 654 ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas); 655 TRACE_EVENT0("android_webview", "RenderToAuxBitmap"); 656 ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap( 657 env, clip.width(), clip.height(), jcanvas, owner_key)); 658 if (!jbitmap.obj()) { 659 TRACE_EVENT_INSTANT0("android_webview", 660 "EarlyOut_BitmapAllocFail", 661 TRACE_EVENT_SCOPE_THREAD); 662 return false; 663 } 664 665 if (!RasterizeIntoBitmap(env, jbitmap, 666 clip.x() - scroll_correction.x(), 667 clip.y() - scroll_correction.y(), 668 render_source)) { 669 TRACE_EVENT_INSTANT0("android_webview", 670 "EarlyOut_RasterizeFail", 671 TRACE_EVENT_SCOPE_THREAD); 672 return false; 673 } 674 675 java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas, 676 clip.x(), clip.y()); 677 return true; 678 } 679 680 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width, 681 int height) { 682 TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture"); 683 684 // Return empty Picture objects for empty SkPictures. 685 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); 686 if (width <= 0 || height <= 0) { 687 return picture; 688 } 689 690 // Reset scroll back to the origin, will go back to the old 691 // value when scroll_reset is out of scope. 692 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_, 693 gfx::Vector2d()); 694 695 SkCanvas* rec_canvas = picture->beginRecording(width, height, 0); 696 if (compositor_) 697 CompositeSW(rec_canvas); 698 picture->endRecording(); 699 return picture; 700 } 701 702 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) { 703 on_new_picture_enable_ = enabled; 704 EnsureContinuousInvalidation(NULL, false); 705 } 706 707 void InProcessViewRenderer::SetIsPaused(bool paused) { 708 TRACE_EVENT_INSTANT1("android_webview", 709 "InProcessViewRenderer::SetIsPaused", 710 TRACE_EVENT_SCOPE_THREAD, 711 "paused", 712 paused); 713 is_paused_ = paused; 714 EnsureContinuousInvalidation(NULL, false); 715 } 716 717 void InProcessViewRenderer::SetViewVisibility(bool view_visible) { 718 TRACE_EVENT_INSTANT1("android_webview", 719 "InProcessViewRenderer::SetViewVisibility", 720 TRACE_EVENT_SCOPE_THREAD, 721 "view_visible", 722 view_visible); 723 view_visible_ = view_visible; 724 } 725 726 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) { 727 TRACE_EVENT_INSTANT1("android_webview", 728 "InProcessViewRenderer::SetWindowVisibility", 729 TRACE_EVENT_SCOPE_THREAD, 730 "window_visible", 731 window_visible); 732 window_visible_ = window_visible; 733 EnsureContinuousInvalidation(NULL, false); 734 } 735 736 void InProcessViewRenderer::OnSizeChanged(int width, int height) { 737 TRACE_EVENT_INSTANT2("android_webview", 738 "InProcessViewRenderer::OnSizeChanged", 739 TRACE_EVENT_SCOPE_THREAD, 740 "width", 741 width, 742 "height", 743 height); 744 width_ = width; 745 height_ = height; 746 } 747 748 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) { 749 TRACE_EVENT2("android_webview", 750 "InProcessViewRenderer::OnAttachedToWindow", 751 "width", 752 width, 753 "height", 754 height); 755 attached_to_window_ = true; 756 width_ = width; 757 height_ = height; 758 } 759 760 void InProcessViewRenderer::OnDetachedFromWindow() { 761 TRACE_EVENT0("android_webview", 762 "InProcessViewRenderer::OnDetachedFromWindow"); 763 764 NoLongerExpectsDrawGL(); 765 if (hardware_initialized_) { 766 DCHECK(compositor_); 767 768 ScopedAppGLStateRestore state_restore( 769 ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT); 770 g_service.Get()->RunTasks(); 771 ScopedAllowGL allow_gl; 772 compositor_->ReleaseHwDraw(); 773 hardware_initialized_ = false; 774 } 775 776 gl_surface_ = NULL; 777 attached_to_window_ = false; 778 } 779 780 bool InProcessViewRenderer::IsAttachedToWindow() { 781 return attached_to_window_; 782 } 783 784 bool InProcessViewRenderer::IsVisible() { 785 // Ignore |window_visible_| if |attached_to_window_| is false. 786 return view_visible_ && (!attached_to_window_ || window_visible_); 787 } 788 789 gfx::Rect InProcessViewRenderer::GetScreenRect() { 790 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_)); 791 } 792 793 void InProcessViewRenderer::DidInitializeCompositor( 794 content::SynchronousCompositor* compositor) { 795 TRACE_EVENT0("android_webview", 796 "InProcessViewRenderer::DidInitializeCompositor"); 797 DCHECK(compositor && compositor_ == NULL); 798 compositor_ = compositor; 799 hardware_initialized_ = false; 800 hardware_failed_ = false; 801 } 802 803 void InProcessViewRenderer::DidDestroyCompositor( 804 content::SynchronousCompositor* compositor) { 805 TRACE_EVENT0("android_webview", 806 "InProcessViewRenderer::DidDestroyCompositor"); 807 DCHECK(compositor_ == compositor); 808 809 // This can fail if Apps call destroy while the webview is still attached 810 // to the view tree. This is an illegal operation that will lead to leaks. 811 // Log for now. Consider a proper fix if this becomes a problem. 812 LOG_IF(ERROR, hardware_initialized_) 813 << "Destroy called before OnDetachedFromWindow. May Leak GL resources"; 814 compositor_ = NULL; 815 } 816 817 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) { 818 if (compositor_needs_continuous_invalidate_ == invalidate) 819 return; 820 821 TRACE_EVENT_INSTANT1("android_webview", 822 "InProcessViewRenderer::SetContinuousInvalidate", 823 TRACE_EVENT_SCOPE_THREAD, 824 "invalidate", 825 invalidate); 826 compositor_needs_continuous_invalidate_ = invalidate; 827 EnsureContinuousInvalidation(NULL, false); 828 } 829 830 void InProcessViewRenderer::SetDipScale(float dip_scale) { 831 dip_scale_ = dip_scale; 832 CHECK(dip_scale_ > 0); 833 } 834 835 gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const { 836 DCHECK_GT(dip_scale_, 0); 837 return gfx::ToCeiledVector2d(gfx::ScaleVector2d( 838 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_)); 839 } 840 841 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) { 842 gfx::Vector2d max_offset = max_scroll_offset(); 843 gfx::Vector2dF scroll_offset_dip; 844 // To preserve the invariant that scrolling to the maximum physical pixel 845 // value also scrolls to the maximum dip pixel value we transform the physical 846 // offset into the dip offset by using a proportion (instead of dividing by 847 // dip_scale * page_scale_factor). 848 if (max_offset.x()) { 849 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) / 850 max_offset.x()); 851 } 852 if (max_offset.y()) { 853 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) / 854 max_offset.y()); 855 } 856 857 DCHECK_LE(0, scroll_offset_dip.x()); 858 DCHECK_LE(0, scroll_offset_dip.y()); 859 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x()); 860 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y()); 861 862 if (scroll_offset_dip_ == scroll_offset_dip) 863 return; 864 865 scroll_offset_dip_ = scroll_offset_dip; 866 867 if (compositor_) 868 compositor_->DidChangeRootLayerScrollOffset(); 869 } 870 871 void InProcessViewRenderer::DidUpdateContent() { 872 if (on_new_picture_enable_) 873 client_->OnNewPicture(); 874 } 875 876 void InProcessViewRenderer::SetMaxRootLayerScrollOffset( 877 gfx::Vector2dF new_value_dip) { 878 DCHECK_GT(dip_scale_, 0); 879 880 max_scroll_offset_dip_ = new_value_dip; 881 DCHECK_LE(0, max_scroll_offset_dip_.x()); 882 DCHECK_LE(0, max_scroll_offset_dip_.y()); 883 884 client_->SetMaxContainerViewScrollOffset(max_scroll_offset()); 885 } 886 887 void InProcessViewRenderer::SetTotalRootLayerScrollOffset( 888 gfx::Vector2dF scroll_offset_dip) { 889 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during 890 // DrawGl when http://crbug.com/249972 is fixed. 891 if (scroll_offset_dip_ == scroll_offset_dip) 892 return; 893 894 scroll_offset_dip_ = scroll_offset_dip; 895 896 gfx::Vector2d max_offset = max_scroll_offset(); 897 gfx::Vector2d scroll_offset; 898 // For an explanation as to why this is done this way see the comment in 899 // InProcessViewRenderer::ScrollTo. 900 if (max_scroll_offset_dip_.x()) { 901 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) / 902 max_scroll_offset_dip_.x()); 903 } 904 905 if (max_scroll_offset_dip_.y()) { 906 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) / 907 max_scroll_offset_dip_.y()); 908 } 909 910 DCHECK(0 <= scroll_offset.x()); 911 DCHECK(0 <= scroll_offset.y()); 912 DCHECK(scroll_offset.x() <= max_offset.x()); 913 DCHECK(scroll_offset.y() <= max_offset.y()); 914 915 client_->ScrollContainerViewTo(scroll_offset); 916 } 917 918 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() { 919 return scroll_offset_dip_; 920 } 921 922 bool InProcessViewRenderer::IsExternalFlingActive() const { 923 return client_->IsFlingActive(); 924 } 925 926 void InProcessViewRenderer::SetRootLayerPageScaleFactor( 927 float page_scale_factor) { 928 page_scale_factor_ = page_scale_factor; 929 DCHECK_GT(page_scale_factor_, 0); 930 client_->SetPageScaleFactor(page_scale_factor); 931 } 932 933 void InProcessViewRenderer::SetRootLayerScrollableSize( 934 gfx::SizeF scrollable_size) { 935 client_->SetContentsSize(scrollable_size); 936 } 937 938 void InProcessViewRenderer::DidOverscroll( 939 gfx::Vector2dF accumulated_overscroll, 940 gfx::Vector2dF latest_overscroll_delta, 941 gfx::Vector2dF current_fling_velocity) { 942 DCHECK(current_fling_velocity.IsZero()); 943 const float physical_pixel_scale = dip_scale_ * page_scale_factor_; 944 if (accumulated_overscroll == latest_overscroll_delta) 945 overscroll_rounding_error_ = gfx::Vector2dF(); 946 gfx::Vector2dF scaled_overscroll_delta = 947 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale); 948 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d( 949 scaled_overscroll_delta + overscroll_rounding_error_); 950 overscroll_rounding_error_ = 951 scaled_overscroll_delta - rounded_overscroll_delta; 952 client_->DidOverscroll(rounded_overscroll_delta); 953 } 954 955 void InProcessViewRenderer::EnsureContinuousInvalidation( 956 AwDrawGLInfo* draw_info, 957 bool invalidate_ignore_compositor) { 958 // This method should be called again when any of these conditions change. 959 bool need_invalidate = 960 compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor; 961 if (!need_invalidate || block_invalidates_) 962 return; 963 964 client_->PostInvalidate(); 965 966 bool throttle_fallback_tick = (is_paused_ && !on_new_picture_enable_) || 967 (attached_to_window_ && !window_visible_); 968 if (throttle_fallback_tick) 969 return; 970 971 block_invalidates_ = compositor_needs_continuous_invalidate_; 972 973 // Unretained here is safe because the callback is cancelled when 974 // |fallback_tick_| is destroyed. 975 fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired, 976 base::Unretained(this))); 977 978 // No need to reschedule fallback tick if compositor does not need to be 979 // ticked. This can happen if this is reached because 980 // invalidate_ignore_compositor is true. 981 if (compositor_needs_continuous_invalidate_) { 982 BrowserThread::PostDelayedTask( 983 BrowserThread::UI, 984 FROM_HERE, 985 fallback_tick_.callback(), 986 base::TimeDelta::FromMilliseconds( 987 kFallbackTickTimeoutInMilliseconds)); 988 } 989 } 990 991 void InProcessViewRenderer::FallbackTickFired() { 992 TRACE_EVENT1("android_webview", 993 "InProcessViewRenderer::FallbackTickFired", 994 "compositor_needs_continuous_invalidate_", 995 compositor_needs_continuous_invalidate_); 996 997 // This should only be called if OnDraw or DrawGL did not come in time, which 998 // means block_invalidates_ must still be true. 999 DCHECK(block_invalidates_); 1000 if (compositor_needs_continuous_invalidate_ && compositor_) 1001 ForceFakeCompositeSW(); 1002 } 1003 1004 void InProcessViewRenderer::ForceFakeCompositeSW() { 1005 DCHECK(compositor_); 1006 SkBitmapDevice device(SkBitmap::kARGB_8888_Config, 1, 1); 1007 SkCanvas canvas(&device); 1008 CompositeSW(&canvas); 1009 } 1010 1011 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) { 1012 DCHECK(compositor_); 1013 1014 fallback_tick_.Cancel(); 1015 block_invalidates_ = true; 1016 bool result = compositor_->DemandDrawSw(canvas); 1017 block_invalidates_ = false; 1018 EnsureContinuousInvalidation(NULL, false); 1019 return result; 1020 } 1021 1022 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const { 1023 std::string str; 1024 base::StringAppendF(&str, "is_paused: %d ", is_paused_); 1025 base::StringAppendF(&str, "view_visible: %d ", view_visible_); 1026 base::StringAppendF(&str, "window_visible: %d ", window_visible_); 1027 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_); 1028 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_); 1029 base::StringAppendF(&str, 1030 "compositor_needs_continuous_invalidate: %d ", 1031 compositor_needs_continuous_invalidate_); 1032 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_); 1033 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_); 1034 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_); 1035 base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_); 1036 base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_); 1037 base::StringAppendF(&str, 1038 "global visible rect: %s ", 1039 cached_global_visible_rect_.ToString().c_str()); 1040 base::StringAppendF(&str, 1041 "scroll_at_start_of_frame: %s ", 1042 scroll_at_start_of_frame_.ToString().c_str()); 1043 base::StringAppendF( 1044 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str()); 1045 base::StringAppendF(&str, 1046 "overscroll_rounding_error_: %s ", 1047 overscroll_rounding_error_.ToString().c_str()); 1048 base::StringAppendF( 1049 &str, "on_new_picture_enable: %d ", on_new_picture_enable_); 1050 if (draw_info) { 1051 base::StringAppendF(&str, 1052 "clip left top right bottom: [%d %d %d %d] ", 1053 draw_info->clip_left, 1054 draw_info->clip_top, 1055 draw_info->clip_right, 1056 draw_info->clip_bottom); 1057 base::StringAppendF(&str, 1058 "surface width height: [%d %d] ", 1059 draw_info->width, 1060 draw_info->height); 1061 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); 1062 } 1063 return str; 1064 } 1065 1066 } // namespace android_webview 1067