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