1 // Copyright 2014 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/browser_view_renderer.h" 6 7 #include "android_webview/browser/browser_view_renderer_client.h" 8 #include "android_webview/browser/shared_renderer_state.h" 9 #include "android_webview/common/aw_switches.h" 10 #include "android_webview/public/browser/draw_gl.h" 11 #include "base/android/jni_android.h" 12 #include "base/auto_reset.h" 13 #include "base/command_line.h" 14 #include "base/debug/trace_event.h" 15 #include "base/json/json_writer.h" 16 #include "base/logging.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/stringprintf.h" 19 #include "cc/output/compositor_frame.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/common/content_switches.h" 23 #include "gpu/command_buffer/service/gpu_switches.h" 24 #include "third_party/skia/include/core/SkBitmap.h" 25 #include "third_party/skia/include/core/SkCanvas.h" 26 #include "third_party/skia/include/core/SkPicture.h" 27 #include "third_party/skia/include/core/SkPictureRecorder.h" 28 #include "ui/gfx/vector2d_conversions.h" 29 30 using base::android::AttachCurrentThread; 31 using base::android::JavaRef; 32 using base::android::ScopedJavaLocalRef; 33 using content::BrowserThread; 34 using content::SynchronousCompositorMemoryPolicy; 35 36 namespace android_webview { 37 38 namespace { 39 40 const int64 kFallbackTickTimeoutInMilliseconds = 100; 41 42 // Used to calculate memory allocation. Determined experimentally. 43 const size_t kMemoryMultiplier = 20; 44 const size_t kBytesPerPixel = 4; 45 const size_t kMemoryAllocationStep = 5 * 1024 * 1024; 46 uint64 g_memory_override_in_bytes = 0u; 47 48 // Used to calculate tile allocation. Determined experimentally. 49 const size_t kTileMultiplier = 12; 50 const size_t kTileAllocationStep = 20; 51 // This will be set by static function CalculateTileMemoryPolicy() during init. 52 // See AwMainDelegate::BasicStartupComplete. 53 size_t g_tile_area; 54 55 class TracedValue : public base::debug::ConvertableToTraceFormat { 56 public: 57 explicit TracedValue(base::Value* value) : value_(value) {} 58 static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue( 59 base::Value* value) { 60 return scoped_refptr<base::debug::ConvertableToTraceFormat>( 61 new TracedValue(value)); 62 } 63 virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE { 64 std::string tmp; 65 base::JSONWriter::Write(value_.get(), &tmp); 66 *out += tmp; 67 } 68 69 private: 70 virtual ~TracedValue() {} 71 scoped_ptr<base::Value> value_; 72 73 DISALLOW_COPY_AND_ASSIGN(TracedValue); 74 }; 75 76 } // namespace 77 78 // static 79 void BrowserViewRenderer::CalculateTileMemoryPolicy(bool use_zero_copy) { 80 CommandLine* cl = CommandLine::ForCurrentProcess(); 81 82 // If the value was overridden on the command line, use the specified value. 83 bool client_hard_limit_bytes_overridden = 84 cl->HasSwitch(switches::kForceGpuMemAvailableMb); 85 if (client_hard_limit_bytes_overridden) { 86 base::StringToUint64( 87 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 88 switches::kForceGpuMemAvailableMb), 89 &g_memory_override_in_bytes); 90 g_memory_override_in_bytes *= 1024 * 1024; 91 } 92 93 if (!use_zero_copy) { 94 // Use chrome's default tile size, which varies from 256 to 512. 95 // Be conservative here and use the smallest tile size possible. 96 g_tile_area = 256 * 256; 97 98 // Also use a high tile limit since there are no file descriptor issues. 99 // There is no need to limit number of tiles, so use an effectively 100 // unlimited value as the limit. 101 GlobalTileManager::GetInstance()->SetTileLimit(10 * 1000 * 1000); 102 return; 103 } 104 105 const char kDefaultTileSize[] = "384"; 106 107 if (!cl->HasSwitch(switches::kDefaultTileWidth)) 108 cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize); 109 110 if (!cl->HasSwitch(switches::kDefaultTileHeight)) 111 cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize); 112 113 size_t tile_size; 114 base::StringToSizeT(kDefaultTileSize, &tile_size); 115 g_tile_area = tile_size * tile_size; 116 } 117 118 BrowserViewRenderer::BrowserViewRenderer( 119 BrowserViewRendererClient* client, 120 SharedRendererState* shared_renderer_state, 121 content::WebContents* web_contents, 122 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) 123 : client_(client), 124 shared_renderer_state_(shared_renderer_state), 125 web_contents_(web_contents), 126 ui_task_runner_(ui_task_runner), 127 compositor_(NULL), 128 is_paused_(false), 129 view_visible_(false), 130 window_visible_(false), 131 attached_to_window_(false), 132 hardware_enabled_(false), 133 dip_scale_(0.0), 134 page_scale_factor_(1.0), 135 on_new_picture_enable_(false), 136 clear_view_(false), 137 compositor_needs_continuous_invalidate_(false), 138 invalidate_after_composite_(false), 139 block_invalidates_(false), 140 fallback_tick_pending_(false), 141 width_(0), 142 height_(0) { 143 CHECK(web_contents_); 144 content::SynchronousCompositor::SetClientForWebContents(web_contents_, this); 145 146 // Currently the logic in this class relies on |compositor_| remaining 147 // NULL until the DidInitializeCompositor() call, hence it is not set here. 148 } 149 150 BrowserViewRenderer::~BrowserViewRenderer() { 151 content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL); 152 // OnDetachedFromWindow should be called before the destructor, so the memory 153 // policy should have already been updated. 154 } 155 156 // This function updates the resource allocation in GlobalTileManager. 157 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) { 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 159 // Constants from Android ComponentCallbacks2. 160 enum { 161 TRIM_MEMORY_RUNNING_LOW = 10, 162 TRIM_MEMORY_UI_HIDDEN = 20, 163 TRIM_MEMORY_BACKGROUND = 40, 164 }; 165 166 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because 167 // it does not indicate memory pressure, but merely that the app is 168 // backgrounded. 169 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN) 170 return; 171 172 // Do not release resources on view we expect to get DrawGL soon. 173 if (level < TRIM_MEMORY_BACKGROUND && visible) 174 return; 175 176 // Just set the memory limit to 0 and drop all tiles. This will be reset to 177 // normal levels in the next DrawGL call. 178 SynchronousCompositorMemoryPolicy zero_policy; 179 if (memory_policy_ == zero_policy) 180 return; 181 182 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory"); 183 DCHECK(hardware_enabled_); 184 DCHECK(compositor_); 185 186 RequestMemoryPolicy(zero_policy); 187 EnforceMemoryPolicyImmediately(zero_policy); 188 } 189 190 SynchronousCompositorMemoryPolicy 191 BrowserViewRenderer::CalculateDesiredMemoryPolicy() { 192 SynchronousCompositorMemoryPolicy policy; 193 size_t width = last_on_draw_global_visible_rect_.width(); 194 size_t height = last_on_draw_global_visible_rect_.height(); 195 policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height; 196 // Round up to a multiple of kMemoryAllocationStep. 197 policy.bytes_limit = 198 (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep; 199 200 if (g_memory_override_in_bytes) 201 policy.bytes_limit = static_cast<size_t>(g_memory_override_in_bytes); 202 203 size_t tiles = width * height * kTileMultiplier / g_tile_area; 204 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles 205 // is also kTileAllocationStep. 206 tiles = (tiles / kTileAllocationStep + 1) * kTileAllocationStep; 207 policy.num_resources_limit = tiles; 208 return policy; 209 } 210 211 // This function updates the cached memory policy in shared renderer state, as 212 // well as the tile resource allocation in GlobalTileManager. 213 void BrowserViewRenderer::RequestMemoryPolicy( 214 SynchronousCompositorMemoryPolicy& new_policy) { 215 DCHECK(compositor_); 216 GlobalTileManager* manager = GlobalTileManager::GetInstance(); 217 218 // The following line will call BrowserViewRenderer::SetMemoryPolicy(). 219 manager->RequestTiles(new_policy, tile_manager_key_); 220 } 221 222 void BrowserViewRenderer::SetMemoryPolicy( 223 SynchronousCompositorMemoryPolicy new_policy, 224 bool effective_immediately) { 225 memory_policy_ = new_policy; 226 if (effective_immediately) 227 EnforceMemoryPolicyImmediately(memory_policy_); 228 } 229 230 void BrowserViewRenderer::EnforceMemoryPolicyImmediately( 231 SynchronousCompositorMemoryPolicy new_policy) { 232 compositor_->SetMemoryPolicy(new_policy); 233 ForceFakeCompositeSW(); 234 } 235 236 SynchronousCompositorMemoryPolicy BrowserViewRenderer::GetMemoryPolicy() const { 237 return memory_policy_; 238 } 239 240 bool BrowserViewRenderer::OnDraw(jobject java_canvas, 241 bool is_hardware_canvas, 242 const gfx::Vector2d& scroll, 243 const gfx::Rect& global_visible_rect) { 244 last_on_draw_scroll_offset_ = scroll; 245 last_on_draw_global_visible_rect_ = global_visible_rect; 246 247 if (clear_view_) 248 return false; 249 250 if (is_hardware_canvas && attached_to_window_ && 251 !switches::ForceAuxiliaryBitmap()) { 252 return OnDrawHardware(java_canvas); 253 } 254 255 // Perform a software draw 256 return OnDrawSoftware(java_canvas); 257 } 258 259 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) { 260 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware"); 261 if (!compositor_) 262 return false; 263 264 shared_renderer_state_->SetScrollOffset(last_on_draw_scroll_offset_); 265 266 if (!hardware_enabled_) { 267 hardware_enabled_ = compositor_->InitializeHwDraw(); 268 if (hardware_enabled_) { 269 tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this); 270 } 271 } 272 if (!hardware_enabled_) 273 return false; 274 275 if (last_on_draw_global_visible_rect_.IsEmpty() && 276 parent_draw_constraints_.surface_rect.IsEmpty()) { 277 TRACE_EVENT_INSTANT0("android_webview", 278 "EarlyOut_EmptyVisibleRect", 279 TRACE_EVENT_SCOPE_THREAD); 280 shared_renderer_state_->SetForceInvalidateOnNextDrawGL(true); 281 return client_->RequestDrawGL(java_canvas, false); 282 } 283 284 ReturnResourceFromParent(); 285 if (shared_renderer_state_->HasCompositorFrame()) { 286 TRACE_EVENT_INSTANT0("android_webview", 287 "EarlyOut_PreviousFrameUnconsumed", 288 TRACE_EVENT_SCOPE_THREAD); 289 DidSkipCompositeInDraw(); 290 return client_->RequestDrawGL(java_canvas, false); 291 } 292 293 scoped_ptr<cc::CompositorFrame> frame = CompositeHw(); 294 if (!frame.get()) 295 return false; 296 297 shared_renderer_state_->SetCompositorFrame(frame.Pass(), false); 298 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_); 299 return client_->RequestDrawGL(java_canvas, false); 300 } 301 302 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() { 303 SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy(); 304 RequestMemoryPolicy(new_policy); 305 compositor_->SetMemoryPolicy(memory_policy_); 306 307 parent_draw_constraints_ = shared_renderer_state_->ParentDrawConstraints(); 308 gfx::Size surface_size(width_, height_); 309 gfx::Rect viewport(surface_size); 310 gfx::Rect clip = viewport; 311 gfx::Transform transform_for_tile_priority = 312 parent_draw_constraints_.transform; 313 314 // If the WebView is on a layer, WebView does not know what transform is 315 // applied onto the layer so global visible rect does not make sense here. 316 // In this case, just use the surface rect for tiling. 317 gfx::Rect viewport_rect_for_tile_priority; 318 if (parent_draw_constraints_.is_layer || 319 last_on_draw_global_visible_rect_.IsEmpty()) { 320 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect; 321 } else { 322 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_; 323 } 324 325 scoped_ptr<cc::CompositorFrame> frame = 326 compositor_->DemandDrawHw(surface_size, 327 gfx::Transform(), 328 viewport, 329 clip, 330 viewport_rect_for_tile_priority, 331 transform_for_tile_priority); 332 if (frame.get()) 333 DidComposite(); 334 return frame.Pass(); 335 } 336 337 void BrowserViewRenderer::UpdateParentDrawConstraints() { 338 // Post an invalidate if the parent draw constraints are stale and there is 339 // no pending invalidate. 340 bool needs_force_invalidate = 341 shared_renderer_state_->NeedsForceInvalidateOnNextDrawGL(); 342 if (needs_force_invalidate || 343 !parent_draw_constraints_.Equals( 344 shared_renderer_state_->ParentDrawConstraints())) { 345 shared_renderer_state_->SetForceInvalidateOnNextDrawGL(false); 346 EnsureContinuousInvalidation(true, needs_force_invalidate); 347 } 348 } 349 350 void BrowserViewRenderer::ReturnUnusedResource( 351 scoped_ptr<cc::CompositorFrame> frame) { 352 if (!frame.get()) 353 return; 354 355 cc::CompositorFrameAck frame_ack; 356 cc::TransferableResource::ReturnResources( 357 frame->delegated_frame_data->resource_list, &frame_ack.resources); 358 if (compositor_ && !frame_ack.resources.empty()) 359 compositor_->ReturnResources(frame_ack); 360 } 361 362 void BrowserViewRenderer::ReturnResourceFromParent() { 363 cc::CompositorFrameAck frame_ack; 364 shared_renderer_state_->SwapReturnedResources(&frame_ack.resources); 365 if (compositor_ && !frame_ack.resources.empty()) { 366 compositor_->ReturnResources(frame_ack); 367 } 368 } 369 370 void BrowserViewRenderer::DidSkipCommitFrame() { 371 // Treat it the same way as skipping onDraw. 372 DidSkipCompositeInDraw(); 373 } 374 375 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) { 376 if (!compositor_) { 377 TRACE_EVENT_INSTANT0( 378 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD); 379 return false; 380 } 381 382 // TODO(hush): right now webview size is passed in as the auxiliary bitmap 383 // size, which might hurt performace (only for software draws with auxiliary 384 // bitmap). For better performance, get global visible rect, transform it 385 // from screen space to view space, then intersect with the webview in 386 // viewspace. Use the resulting rect as the auxiliary 387 // bitmap. 388 return BrowserViewRendererJavaHelper::GetInstance() 389 ->RenderViaAuxilaryBitmapIfNeeded( 390 java_canvas, 391 last_on_draw_scroll_offset_, 392 gfx::Size(width_, height_), 393 base::Bind(&BrowserViewRenderer::CompositeSW, 394 base::Unretained(this))); 395 } 396 397 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width, 398 int height) { 399 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture"); 400 401 // Return empty Picture objects for empty SkPictures. 402 if (width <= 0 || height <= 0) { 403 SkPictureRecorder emptyRecorder; 404 emptyRecorder.beginRecording(0, 0); 405 return skia::AdoptRef(emptyRecorder.endRecording()); 406 } 407 408 // Reset scroll back to the origin, will go back to the old 409 // value when scroll_reset is out of scope. 410 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_, 411 gfx::Vector2dF()); 412 413 SkPictureRecorder recorder; 414 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0); 415 if (compositor_) 416 CompositeSW(rec_canvas); 417 return skia::AdoptRef(recorder.endRecording()); 418 } 419 420 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) { 421 on_new_picture_enable_ = enabled; 422 } 423 424 void BrowserViewRenderer::ClearView() { 425 TRACE_EVENT_INSTANT0("android_webview", 426 "BrowserViewRenderer::ClearView", 427 TRACE_EVENT_SCOPE_THREAD); 428 if (clear_view_) 429 return; 430 431 clear_view_ = true; 432 // Always invalidate ignoring the compositor to actually clear the webview. 433 EnsureContinuousInvalidation(true, false); 434 } 435 436 void BrowserViewRenderer::SetIsPaused(bool paused) { 437 TRACE_EVENT_INSTANT1("android_webview", 438 "BrowserViewRenderer::SetIsPaused", 439 TRACE_EVENT_SCOPE_THREAD, 440 "paused", 441 paused); 442 is_paused_ = paused; 443 EnsureContinuousInvalidation(false, false); 444 } 445 446 void BrowserViewRenderer::SetViewVisibility(bool view_visible) { 447 TRACE_EVENT_INSTANT1("android_webview", 448 "BrowserViewRenderer::SetViewVisibility", 449 TRACE_EVENT_SCOPE_THREAD, 450 "view_visible", 451 view_visible); 452 view_visible_ = view_visible; 453 } 454 455 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) { 456 TRACE_EVENT_INSTANT1("android_webview", 457 "BrowserViewRenderer::SetWindowVisibility", 458 TRACE_EVENT_SCOPE_THREAD, 459 "window_visible", 460 window_visible); 461 window_visible_ = window_visible; 462 EnsureContinuousInvalidation(false, false); 463 } 464 465 void BrowserViewRenderer::OnSizeChanged(int width, int height) { 466 TRACE_EVENT_INSTANT2("android_webview", 467 "BrowserViewRenderer::OnSizeChanged", 468 TRACE_EVENT_SCOPE_THREAD, 469 "width", 470 width, 471 "height", 472 height); 473 width_ = width; 474 height_ = height; 475 } 476 477 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) { 478 TRACE_EVENT2("android_webview", 479 "BrowserViewRenderer::OnAttachedToWindow", 480 "width", 481 width, 482 "height", 483 height); 484 attached_to_window_ = true; 485 width_ = width; 486 height_ = height; 487 } 488 489 void BrowserViewRenderer::OnDetachedFromWindow() { 490 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow"); 491 attached_to_window_ = false; 492 DCHECK(!hardware_enabled_); 493 } 494 495 void BrowserViewRenderer::ReleaseHardware() { 496 DCHECK(hardware_enabled_); 497 ReturnUnusedResource(shared_renderer_state_->PassCompositorFrame()); 498 ReturnResourceFromParent(); 499 DCHECK(shared_renderer_state_->ReturnedResourcesEmpty()); 500 501 if (compositor_) { 502 compositor_->ReleaseHwDraw(); 503 SynchronousCompositorMemoryPolicy zero_policy; 504 RequestMemoryPolicy(zero_policy); 505 } 506 507 hardware_enabled_ = false; 508 GlobalTileManager::GetInstance()->Remove(tile_manager_key_); 509 } 510 511 bool BrowserViewRenderer::IsVisible() const { 512 // Ignore |window_visible_| if |attached_to_window_| is false. 513 return view_visible_ && (!attached_to_window_ || window_visible_); 514 } 515 516 gfx::Rect BrowserViewRenderer::GetScreenRect() const { 517 return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_)); 518 } 519 520 void BrowserViewRenderer::DidInitializeCompositor( 521 content::SynchronousCompositor* compositor) { 522 TRACE_EVENT0("android_webview", 523 "BrowserViewRenderer::DidInitializeCompositor"); 524 DCHECK(compositor); 525 DCHECK(!compositor_); 526 compositor_ = compositor; 527 } 528 529 void BrowserViewRenderer::DidDestroyCompositor( 530 content::SynchronousCompositor* compositor) { 531 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor"); 532 DCHECK(compositor_); 533 SynchronousCompositorMemoryPolicy zero_policy; 534 if (hardware_enabled_) { 535 RequestMemoryPolicy(zero_policy); 536 } 537 DCHECK(memory_policy_ == zero_policy); 538 compositor_ = NULL; 539 } 540 541 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) { 542 if (compositor_needs_continuous_invalidate_ == invalidate) 543 return; 544 545 TRACE_EVENT_INSTANT1("android_webview", 546 "BrowserViewRenderer::SetContinuousInvalidate", 547 TRACE_EVENT_SCOPE_THREAD, 548 "invalidate", 549 invalidate); 550 compositor_needs_continuous_invalidate_ = invalidate; 551 552 EnsureContinuousInvalidation(false, false); 553 } 554 555 void BrowserViewRenderer::SetDipScale(float dip_scale) { 556 dip_scale_ = dip_scale; 557 CHECK_GT(dip_scale_, 0); 558 } 559 560 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const { 561 DCHECK_GT(dip_scale_, 0); 562 return gfx::ToCeiledVector2d(gfx::ScaleVector2d( 563 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_)); 564 } 565 566 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) { 567 gfx::Vector2d max_offset = max_scroll_offset(); 568 gfx::Vector2dF scroll_offset_dip; 569 // To preserve the invariant that scrolling to the maximum physical pixel 570 // value also scrolls to the maximum dip pixel value we transform the physical 571 // offset into the dip offset by using a proportion (instead of dividing by 572 // dip_scale * page_scale_factor). 573 if (max_offset.x()) { 574 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) / 575 max_offset.x()); 576 } 577 if (max_offset.y()) { 578 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) / 579 max_offset.y()); 580 } 581 582 DCHECK_LE(0, scroll_offset_dip.x()); 583 DCHECK_LE(0, scroll_offset_dip.y()); 584 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x()); 585 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y()); 586 587 if (scroll_offset_dip_ == scroll_offset_dip) 588 return; 589 590 scroll_offset_dip_ = scroll_offset_dip; 591 592 TRACE_EVENT_INSTANT2("android_webview", 593 "BrowserViewRenderer::ScrollTo", 594 TRACE_EVENT_SCOPE_THREAD, 595 "x", 596 scroll_offset_dip.x(), 597 "y", 598 scroll_offset_dip.y()); 599 600 if (compositor_) 601 compositor_->DidChangeRootLayerScrollOffset(); 602 } 603 604 void BrowserViewRenderer::DidUpdateContent() { 605 TRACE_EVENT_INSTANT0("android_webview", 606 "BrowserViewRenderer::DidUpdateContent", 607 TRACE_EVENT_SCOPE_THREAD); 608 clear_view_ = false; 609 if (on_new_picture_enable_) 610 client_->OnNewPicture(); 611 } 612 613 void BrowserViewRenderer::SetTotalRootLayerScrollOffset( 614 gfx::Vector2dF scroll_offset_dip) { 615 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during 616 // DrawGl when http://crbug.com/249972 is fixed. 617 if (scroll_offset_dip_ == scroll_offset_dip) 618 return; 619 620 scroll_offset_dip_ = scroll_offset_dip; 621 622 gfx::Vector2d max_offset = max_scroll_offset(); 623 gfx::Vector2d scroll_offset; 624 // For an explanation as to why this is done this way see the comment in 625 // BrowserViewRenderer::ScrollTo. 626 if (max_scroll_offset_dip_.x()) { 627 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) / 628 max_scroll_offset_dip_.x()); 629 } 630 631 if (max_scroll_offset_dip_.y()) { 632 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) / 633 max_scroll_offset_dip_.y()); 634 } 635 636 DCHECK_LE(0, scroll_offset.x()); 637 DCHECK_LE(0, scroll_offset.y()); 638 DCHECK_LE(scroll_offset.x(), max_offset.x()); 639 DCHECK_LE(scroll_offset.y(), max_offset.y()); 640 641 client_->ScrollContainerViewTo(scroll_offset); 642 } 643 644 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() { 645 return scroll_offset_dip_; 646 } 647 648 bool BrowserViewRenderer::IsExternalFlingActive() const { 649 return client_->IsFlingActive(); 650 } 651 652 void BrowserViewRenderer::UpdateRootLayerState( 653 const gfx::Vector2dF& total_scroll_offset_dip, 654 const gfx::Vector2dF& max_scroll_offset_dip, 655 const gfx::SizeF& scrollable_size_dip, 656 float page_scale_factor, 657 float min_page_scale_factor, 658 float max_page_scale_factor) { 659 TRACE_EVENT_INSTANT1( 660 "android_webview", 661 "BrowserViewRenderer::UpdateRootLayerState", 662 TRACE_EVENT_SCOPE_THREAD, 663 "state", 664 TracedValue::FromValue( 665 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip) 666 .release())); 667 668 DCHECK_GT(dip_scale_, 0); 669 670 max_scroll_offset_dip_ = max_scroll_offset_dip; 671 DCHECK_LE(0, max_scroll_offset_dip_.x()); 672 DCHECK_LE(0, max_scroll_offset_dip_.y()); 673 674 page_scale_factor_ = page_scale_factor; 675 DCHECK_GT(page_scale_factor_, 0); 676 677 client_->UpdateScrollState(max_scroll_offset(), 678 scrollable_size_dip, 679 page_scale_factor, 680 min_page_scale_factor, 681 max_page_scale_factor); 682 SetTotalRootLayerScrollOffset(total_scroll_offset_dip); 683 } 684 685 scoped_ptr<base::Value> BrowserViewRenderer::RootLayerStateAsValue( 686 const gfx::Vector2dF& total_scroll_offset_dip, 687 const gfx::SizeF& scrollable_size_dip) { 688 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); 689 690 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x()); 691 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y()); 692 693 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x()); 694 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y()); 695 696 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width()); 697 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height()); 698 699 state->SetDouble("page_scale_factor", page_scale_factor_); 700 return state.PassAs<base::Value>(); 701 } 702 703 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll, 704 gfx::Vector2dF latest_overscroll_delta, 705 gfx::Vector2dF current_fling_velocity) { 706 const float physical_pixel_scale = dip_scale_ * page_scale_factor_; 707 if (accumulated_overscroll == latest_overscroll_delta) 708 overscroll_rounding_error_ = gfx::Vector2dF(); 709 gfx::Vector2dF scaled_overscroll_delta = 710 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale); 711 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d( 712 scaled_overscroll_delta + overscroll_rounding_error_); 713 overscroll_rounding_error_ = 714 scaled_overscroll_delta - rounded_overscroll_delta; 715 client_->DidOverscroll(rounded_overscroll_delta); 716 } 717 718 void BrowserViewRenderer::EnsureContinuousInvalidation( 719 bool force_invalidate, 720 bool skip_reschedule_tick) { 721 if (force_invalidate) 722 invalidate_after_composite_ = true; 723 724 // This method should be called again when any of these conditions change. 725 bool need_invalidate = 726 compositor_needs_continuous_invalidate_ || invalidate_after_composite_; 727 if (!need_invalidate || block_invalidates_) 728 return; 729 730 if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_) 731 invalidate_after_composite_ = false; 732 733 // Always call view invalidate. We rely the Android framework to ignore the 734 // invalidate when it's not needed such as when view is not visible. 735 client_->PostInvalidate(); 736 737 // Stop fallback ticks when one of these is true. 738 // 1) Webview is paused. Also need to check we are not in clear view since 739 // paused, offscreen still expect clear view to recover. 740 // 2) If we are attached to window and the window is not visible (eg when 741 // app is in the background). We are sure in this case the webview is used 742 // "on-screen" but that updates are not needed when in the background. 743 bool throttle_fallback_tick = 744 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_); 745 if (throttle_fallback_tick) 746 return; 747 748 block_invalidates_ = compositor_needs_continuous_invalidate_; 749 if (skip_reschedule_tick && fallback_tick_pending_) 750 return; 751 752 // Unretained here is safe because the callbacks are cancelled when 753 // they are destroyed. 754 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick, 755 base::Unretained(this))); 756 fallback_tick_fired_.Cancel(); 757 fallback_tick_pending_ = false; 758 759 // No need to reschedule fallback tick if compositor does not need to be 760 // ticked. This can happen if this is reached because force_invalidate is 761 // true. 762 if (compositor_needs_continuous_invalidate_) { 763 fallback_tick_pending_ = true; 764 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback()); 765 } 766 } 767 768 void BrowserViewRenderer::PostFallbackTick() { 769 DCHECK(fallback_tick_fired_.IsCancelled()); 770 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired, 771 base::Unretained(this))); 772 if (compositor_needs_continuous_invalidate_) { 773 ui_task_runner_->PostDelayedTask( 774 FROM_HERE, 775 fallback_tick_fired_.callback(), 776 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds)); 777 } else { 778 // Pretend we just composited to unblock further invalidates. 779 DidComposite(); 780 } 781 } 782 783 void BrowserViewRenderer::FallbackTickFired() { 784 TRACE_EVENT1("android_webview", 785 "BrowserViewRenderer::FallbackTickFired", 786 "compositor_needs_continuous_invalidate_", 787 compositor_needs_continuous_invalidate_); 788 789 // This should only be called if OnDraw or DrawGL did not come in time, which 790 // means block_invalidates_ must still be true. 791 DCHECK(block_invalidates_); 792 fallback_tick_pending_ = false; 793 if (compositor_needs_continuous_invalidate_ && compositor_) { 794 if (hardware_enabled_) { 795 ReturnResourceFromParent(); 796 ReturnUnusedResource(shared_renderer_state_->PassCompositorFrame()); 797 scoped_ptr<cc::CompositorFrame> frame = CompositeHw(); 798 if (frame.get()) { 799 shared_renderer_state_->SetCompositorFrame(frame.Pass(), true); 800 } 801 } else { 802 ForceFakeCompositeSW(); 803 } 804 } else { 805 // Pretend we just composited to unblock further invalidates. 806 DidComposite(); 807 } 808 } 809 810 void BrowserViewRenderer::ForceFakeCompositeSW() { 811 DCHECK(compositor_); 812 SkBitmap bitmap; 813 bitmap.allocN32Pixels(1, 1); 814 bitmap.eraseColor(0); 815 SkCanvas canvas(bitmap); 816 CompositeSW(&canvas); 817 } 818 819 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) { 820 DCHECK(compositor_); 821 ReturnResourceFromParent(); 822 bool result = compositor_->DemandDrawSw(canvas); 823 DidComposite(); 824 return result; 825 } 826 827 void BrowserViewRenderer::DidComposite() { 828 block_invalidates_ = false; 829 post_fallback_tick_.Cancel(); 830 fallback_tick_fired_.Cancel(); 831 fallback_tick_pending_ = false; 832 EnsureContinuousInvalidation(false, false); 833 } 834 835 void BrowserViewRenderer::DidSkipCompositeInDraw() { 836 block_invalidates_ = false; 837 EnsureContinuousInvalidation(true, true); 838 } 839 840 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const { 841 std::string str; 842 base::StringAppendF(&str, "is_paused: %d ", is_paused_); 843 base::StringAppendF(&str, "view_visible: %d ", view_visible_); 844 base::StringAppendF(&str, "window_visible: %d ", window_visible_); 845 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_); 846 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_); 847 base::StringAppendF(&str, 848 "compositor_needs_continuous_invalidate: %d ", 849 compositor_needs_continuous_invalidate_); 850 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_); 851 base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_); 852 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_); 853 base::StringAppendF(&str, 854 "global visible rect: %s ", 855 last_on_draw_global_visible_rect_.ToString().c_str()); 856 base::StringAppendF( 857 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str()); 858 base::StringAppendF(&str, 859 "overscroll_rounding_error_: %s ", 860 overscroll_rounding_error_.ToString().c_str()); 861 base::StringAppendF( 862 &str, "on_new_picture_enable: %d ", on_new_picture_enable_); 863 base::StringAppendF(&str, "clear_view: %d ", clear_view_); 864 if (draw_info) { 865 base::StringAppendF(&str, 866 "clip left top right bottom: [%d %d %d %d] ", 867 draw_info->clip_left, 868 draw_info->clip_top, 869 draw_info->clip_right, 870 draw_info->clip_bottom); 871 base::StringAppendF(&str, 872 "surface width height: [%d %d] ", 873 draw_info->width, 874 draw_info->height); 875 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer); 876 } 877 return str; 878 } 879 880 } // namespace android_webview 881