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