1 // Copyright (c) 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 "content/renderer/gpu/render_widget_compositor.h" 6 7 #include <limits> 8 #include <string> 9 10 #include "base/command_line.h" 11 #include "base/logging.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/synchronization/lock.h" 14 #include "base/time/time.h" 15 #include "cc/base/switches.h" 16 #include "cc/debug/layer_tree_debug_state.h" 17 #include "cc/layers/layer.h" 18 #include "cc/trees/layer_tree_host.h" 19 #include "content/common/gpu/client/context_provider_command_buffer.h" 20 #include "content/public/common/content_switches.h" 21 #include "content/renderer/gpu/input_handler_manager.h" 22 #include "content/renderer/render_thread_impl.h" 23 #include "third_party/WebKit/public/platform/WebSize.h" 24 #include "third_party/WebKit/public/web/WebWidget.h" 25 #include "ui/gl/gl_switches.h" 26 #include "webkit/renderer/compositor_bindings/web_layer_impl.h" 27 28 namespace cc { 29 class Layer; 30 } 31 32 using WebKit::WebFloatPoint; 33 using WebKit::WebSize; 34 using WebKit::WebRect; 35 36 namespace content { 37 namespace { 38 39 bool GetSwitchValueAsInt( 40 const CommandLine& command_line, 41 const std::string& switch_string, 42 int min_value, 43 int max_value, 44 int* result) { 45 std::string string_value = command_line.GetSwitchValueASCII(switch_string); 46 int int_value; 47 if (base::StringToInt(string_value, &int_value) && 48 int_value >= min_value && int_value <= max_value) { 49 *result = int_value; 50 return true; 51 } else { 52 LOG(WARNING) << "Failed to parse switch " << switch_string << ": " << 53 string_value; 54 return false; 55 } 56 } 57 58 bool GetSwitchValueAsFloat( 59 const CommandLine& command_line, 60 const std::string& switch_string, 61 float min_value, 62 float max_value, 63 float* result) { 64 std::string string_value = command_line.GetSwitchValueASCII(switch_string); 65 double double_value; 66 if (base::StringToDouble(string_value, &double_value) && 67 double_value >= min_value && double_value <= max_value) { 68 *result = static_cast<float>(double_value); 69 return true; 70 } else { 71 LOG(WARNING) << "Failed to parse switch " << switch_string << ": " << 72 string_value; 73 return false; 74 } 75 } 76 77 78 } // namespace 79 80 // static 81 scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create( 82 RenderWidget* widget, 83 bool threaded) { 84 scoped_ptr<RenderWidgetCompositor> compositor( 85 new RenderWidgetCompositor(widget, threaded)); 86 87 CommandLine* cmd = CommandLine::ForCurrentProcess(); 88 89 cc::LayerTreeSettings settings; 90 91 // For web contents, layer transforms should scale up the contents of layers 92 // to keep content always crisp when possible. 93 settings.layer_transforms_should_scale_layer_contents = true; 94 95 settings.throttle_frame_production = 96 !cmd->HasSwitch(switches::kDisableGpuVsync); 97 settings.begin_frame_scheduling_enabled = 98 cmd->HasSwitch(switches::kEnableBeginFrameScheduling); 99 settings.using_synchronous_renderer_compositor = 100 widget->UsingSynchronousRendererCompositor(); 101 settings.per_tile_painting_enabled = 102 cmd->HasSwitch(cc::switches::kEnablePerTilePainting); 103 settings.accelerated_animation_enabled = 104 !cmd->HasSwitch(cc::switches::kDisableThreadedAnimation); 105 settings.force_direct_layer_drawing = 106 cmd->HasSwitch(cc::switches::kForceDirectLayerDrawing); 107 settings.touch_hit_testing = 108 !cmd->HasSwitch(cc::switches::kDisableCompositorTouchHitTesting); 109 110 int default_tile_width = settings.default_tile_size.width(); 111 if (cmd->HasSwitch(switches::kDefaultTileWidth)) { 112 GetSwitchValueAsInt(*cmd, switches::kDefaultTileWidth, 1, 113 std::numeric_limits<int>::max(), &default_tile_width); 114 } 115 int default_tile_height = settings.default_tile_size.height(); 116 if (cmd->HasSwitch(switches::kDefaultTileHeight)) { 117 GetSwitchValueAsInt(*cmd, switches::kDefaultTileHeight, 1, 118 std::numeric_limits<int>::max(), &default_tile_height); 119 } 120 settings.default_tile_size = gfx::Size(default_tile_width, 121 default_tile_height); 122 123 int max_untiled_layer_width = settings.max_untiled_layer_size.width(); 124 if (cmd->HasSwitch(switches::kMaxUntiledLayerWidth)) { 125 GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerWidth, 1, 126 std::numeric_limits<int>::max(), 127 &max_untiled_layer_width); 128 } 129 int max_untiled_layer_height = settings.max_untiled_layer_size.height(); 130 if (cmd->HasSwitch(switches::kMaxUntiledLayerHeight)) { 131 GetSwitchValueAsInt(*cmd, switches::kMaxUntiledLayerHeight, 1, 132 std::numeric_limits<int>::max(), 133 &max_untiled_layer_height); 134 } 135 136 settings.max_untiled_layer_size = gfx::Size(max_untiled_layer_width, 137 max_untiled_layer_height); 138 139 settings.impl_side_painting = cc::switches::IsImplSidePaintingEnabled(); 140 141 settings.calculate_top_controls_position = 142 cmd->HasSwitch(cc::switches::kEnableTopControlsPositionCalculation); 143 if (cmd->HasSwitch(cc::switches::kTopControlsHeight)) { 144 std::string controls_height_str = 145 cmd->GetSwitchValueASCII(cc::switches::kTopControlsHeight); 146 double controls_height; 147 if (base::StringToDouble(controls_height_str, &controls_height) && 148 controls_height > 0) 149 settings.top_controls_height = controls_height; 150 } 151 152 if (settings.calculate_top_controls_position && 153 settings.top_controls_height <= 0) { 154 DCHECK(false) 155 << "Top controls repositioning enabled without valid height set."; 156 settings.calculate_top_controls_position = false; 157 } 158 159 if (cmd->HasSwitch(cc::switches::kTopControlsShowThreshold)) { 160 std::string top_threshold_str = 161 cmd->GetSwitchValueASCII(cc::switches::kTopControlsShowThreshold); 162 double show_threshold; 163 if (base::StringToDouble(top_threshold_str, &show_threshold) && 164 show_threshold >= 0.f && show_threshold <= 1.f) 165 settings.top_controls_show_threshold = show_threshold; 166 } 167 168 if (cmd->HasSwitch(cc::switches::kTopControlsHideThreshold)) { 169 std::string top_threshold_str = 170 cmd->GetSwitchValueASCII(cc::switches::kTopControlsHideThreshold); 171 double hide_threshold; 172 if (base::StringToDouble(top_threshold_str, &hide_threshold) && 173 hide_threshold >= 0.f && hide_threshold <= 1.f) 174 settings.top_controls_hide_threshold = hide_threshold; 175 } 176 177 settings.partial_swap_enabled = widget->AllowPartialSwap() && 178 cmd->HasSwitch(cc::switches::kEnablePartialSwap); 179 settings.background_color_instead_of_checkerboard = 180 cmd->HasSwitch(cc::switches::kBackgroundColorInsteadOfCheckerboard); 181 settings.show_overdraw_in_tracing = 182 cmd->HasSwitch(cc::switches::kTraceOverdraw); 183 settings.use_pinch_virtual_viewport = 184 cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport); 185 settings.allow_antialiasing &= 186 !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing); 187 188 // These flags should be mirrored by UI versions in ui/compositor/. 189 settings.initial_debug_state.show_debug_borders = 190 cmd->HasSwitch(cc::switches::kShowCompositedLayerBorders); 191 settings.initial_debug_state.show_fps_counter = 192 cmd->HasSwitch(cc::switches::kShowFPSCounter); 193 settings.initial_debug_state.show_paint_rects = 194 cmd->HasSwitch(switches::kShowPaintRects); 195 settings.initial_debug_state.show_property_changed_rects = 196 cmd->HasSwitch(cc::switches::kShowPropertyChangedRects); 197 settings.initial_debug_state.show_surface_damage_rects = 198 cmd->HasSwitch(cc::switches::kShowSurfaceDamageRects); 199 settings.initial_debug_state.show_screen_space_rects = 200 cmd->HasSwitch(cc::switches::kShowScreenSpaceRects); 201 settings.initial_debug_state.show_replica_screen_space_rects = 202 cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects); 203 settings.initial_debug_state.show_occluding_rects = 204 cmd->HasSwitch(cc::switches::kShowOccludingRects); 205 settings.initial_debug_state.show_non_occluding_rects = 206 cmd->HasSwitch(cc::switches::kShowNonOccludingRects); 207 208 settings.initial_debug_state.SetRecordRenderingStats( 209 cmd->HasSwitch(switches::kEnableGpuBenchmarking)); 210 211 if (cmd->HasSwitch(cc::switches::kSlowDownRasterScaleFactor)) { 212 const int kMinSlowDownScaleFactor = 0; 213 const int kMaxSlowDownScaleFactor = INT_MAX; 214 GetSwitchValueAsInt( 215 *cmd, 216 cc::switches::kSlowDownRasterScaleFactor, 217 kMinSlowDownScaleFactor, 218 kMaxSlowDownScaleFactor, 219 &settings.initial_debug_state.slow_down_raster_scale_factor); 220 } 221 222 if (cmd->HasSwitch(cc::switches::kNumRasterThreads)) { 223 const int kMinRasterThreads = 1; 224 const int kMaxRasterThreads = 64; 225 int num_raster_threads; 226 if (GetSwitchValueAsInt(*cmd, cc::switches::kNumRasterThreads, 227 kMinRasterThreads, kMaxRasterThreads, 228 &num_raster_threads)) 229 settings.num_raster_threads = num_raster_threads; 230 } 231 232 if (cmd->HasSwitch(cc::switches::kLowResolutionContentsScaleFactor)) { 233 const int kMinScaleFactor = settings.minimum_contents_scale; 234 const int kMaxScaleFactor = 1; 235 GetSwitchValueAsFloat(*cmd, 236 cc::switches::kLowResolutionContentsScaleFactor, 237 kMinScaleFactor, kMaxScaleFactor, 238 &settings.low_res_contents_scale_factor); 239 } 240 241 if (cmd->HasSwitch(cc::switches::kMaxTilesForInterestArea)) { 242 int max_tiles_for_interest_area; 243 if (GetSwitchValueAsInt(*cmd, 244 cc::switches::kMaxTilesForInterestArea, 245 1, std::numeric_limits<int>::max(), 246 &max_tiles_for_interest_area)) 247 settings.max_tiles_for_interest_area = max_tiles_for_interest_area; 248 } 249 250 if (cmd->HasSwitch(cc::switches::kMaxUnusedResourceMemoryUsagePercentage)) { 251 int max_unused_resource_memory_percentage; 252 if (GetSwitchValueAsInt( 253 *cmd, 254 cc::switches::kMaxUnusedResourceMemoryUsagePercentage, 255 0, 100, 256 &max_unused_resource_memory_percentage)) { 257 settings.max_unused_resource_memory_percentage = 258 max_unused_resource_memory_percentage; 259 } 260 } 261 262 settings.strict_layer_property_change_checking = 263 cmd->HasSwitch(cc::switches::kStrictLayerPropertyChangeChecking); 264 265 settings.use_map_image = cmd->HasSwitch(cc::switches::kUseMapImage); 266 267 #if defined(OS_ANDROID) 268 // TODO(danakj): Move these to the android code. 269 settings.can_use_lcd_text = false; 270 settings.max_partial_texture_updates = 0; 271 settings.use_linear_fade_scrollbar_animator = true; 272 settings.solid_color_scrollbars = true; 273 settings.solid_color_scrollbar_color = 274 cmd->HasSwitch(switches::kHideScrollbars) 275 ? SK_ColorTRANSPARENT 276 : SkColorSetARGB(128, 128, 128, 128); 277 settings.solid_color_scrollbar_thickness_dip = 3; 278 settings.highp_threshold_min = 2048; 279 // Android WebView handles root layer flings itself. 280 settings.ignore_root_layer_flings = 281 widget->UsingSynchronousRendererCompositor(); 282 settings.always_overscroll = widget->UsingSynchronousRendererCompositor(); 283 #elif !defined(OS_MACOSX) 284 if (cmd->HasSwitch(switches::kEnableOverlayScrollbars)) { 285 settings.use_linear_fade_scrollbar_animator = true; 286 settings.solid_color_scrollbars = true; 287 settings.solid_color_scrollbar_color = SkColorSetARGB(128, 128, 128, 128); 288 settings.solid_color_scrollbar_thickness_dip = 3; 289 } 290 #endif 291 292 if (!compositor->initialize(settings)) 293 return scoped_ptr<RenderWidgetCompositor>(); 294 295 return compositor.Pass(); 296 } 297 298 RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget, 299 bool threaded) 300 : threaded_(threaded), 301 suppress_schedule_composite_(false), 302 widget_(widget) { 303 } 304 305 RenderWidgetCompositor::~RenderWidgetCompositor() {} 306 307 const base::WeakPtr<cc::InputHandler>& 308 RenderWidgetCompositor::GetInputHandler() { 309 return layer_tree_host_->GetInputHandler(); 310 } 311 312 void RenderWidgetCompositor::SetSuppressScheduleComposite(bool suppress) { 313 if (suppress_schedule_composite_ == suppress) 314 return; 315 316 if (suppress) 317 TRACE_EVENT_ASYNC_BEGIN0("gpu", 318 "RenderWidgetCompositor::SetSuppressScheduleComposite", this); 319 else 320 TRACE_EVENT_ASYNC_END0("gpu", 321 "RenderWidgetCompositor::SetSuppressScheduleComposite", this); 322 suppress_schedule_composite_ = suppress; 323 } 324 325 void RenderWidgetCompositor::Animate(base::TimeTicks time) { 326 layer_tree_host_->UpdateClientAnimations(time); 327 } 328 329 void RenderWidgetCompositor::Composite(base::TimeTicks frame_begin_time) { 330 layer_tree_host_->Composite(frame_begin_time); 331 } 332 333 void RenderWidgetCompositor::SetNeedsDisplayOnAllLayers() { 334 layer_tree_host_->SetNeedsDisplayOnAllLayers(); 335 } 336 337 void RenderWidgetCompositor::SetRasterizeOnlyVisibleContent() { 338 cc::LayerTreeDebugState current = layer_tree_host_->debug_state(); 339 current.rasterize_only_visible_content = true; 340 layer_tree_host_->SetDebugState(current); 341 } 342 343 void RenderWidgetCompositor::GetRenderingStats(cc::RenderingStats* stats) { 344 layer_tree_host_->CollectRenderingStats(stats); 345 } 346 347 void RenderWidgetCompositor::UpdateTopControlsState( 348 cc::TopControlsState constraints, 349 cc::TopControlsState current, 350 bool animate) { 351 layer_tree_host_->UpdateTopControlsState(constraints, 352 current, 353 animate); 354 } 355 356 void RenderWidgetCompositor::SetOverdrawBottomHeight( 357 float overdraw_bottom_height) { 358 layer_tree_host_->SetOverdrawBottomHeight(overdraw_bottom_height); 359 } 360 361 void RenderWidgetCompositor::SetNeedsRedrawRect(gfx::Rect damage_rect) { 362 layer_tree_host_->SetNeedsRedrawRect(damage_rect); 363 } 364 365 void RenderWidgetCompositor::SetLatencyInfo( 366 const ui::LatencyInfo& latency_info) { 367 layer_tree_host_->SetLatencyInfo(latency_info); 368 } 369 370 int RenderWidgetCompositor::GetLayerTreeId() const { 371 return layer_tree_host_->id(); 372 } 373 374 void RenderWidgetCompositor::NotifyInputThrottledUntilCommit() { 375 layer_tree_host_->NotifyInputThrottledUntilCommit(); 376 } 377 378 bool RenderWidgetCompositor::initialize(cc::LayerTreeSettings settings) { 379 scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy = 380 RenderThreadImpl::current()->compositor_message_loop_proxy(); 381 layer_tree_host_ = cc::LayerTreeHost::Create(this, 382 settings, 383 compositor_message_loop_proxy); 384 return layer_tree_host_; 385 } 386 387 void RenderWidgetCompositor::setSurfaceReady() { 388 layer_tree_host_->SetLayerTreeHostClientReady(); 389 } 390 391 void RenderWidgetCompositor::setRootLayer(const WebKit::WebLayer& layer) { 392 layer_tree_host_->SetRootLayer( 393 static_cast<const webkit::WebLayerImpl*>(&layer)->layer()); 394 } 395 396 void RenderWidgetCompositor::clearRootLayer() { 397 layer_tree_host_->SetRootLayer(scoped_refptr<cc::Layer>()); 398 } 399 400 void RenderWidgetCompositor::setViewportSize( 401 const WebSize&, 402 const WebSize& device_viewport_size) { 403 layer_tree_host_->SetViewportSize(device_viewport_size); 404 } 405 406 WebSize RenderWidgetCompositor::layoutViewportSize() const { 407 return layer_tree_host_->device_viewport_size(); 408 } 409 410 WebSize RenderWidgetCompositor::deviceViewportSize() const { 411 return layer_tree_host_->device_viewport_size(); 412 } 413 414 WebFloatPoint RenderWidgetCompositor::adjustEventPointForPinchZoom( 415 const WebFloatPoint& point) const { 416 return point; 417 } 418 419 void RenderWidgetCompositor::setDeviceScaleFactor(float device_scale) { 420 layer_tree_host_->SetDeviceScaleFactor(device_scale); 421 } 422 423 float RenderWidgetCompositor::deviceScaleFactor() const { 424 return layer_tree_host_->device_scale_factor(); 425 } 426 427 void RenderWidgetCompositor::setBackgroundColor(WebKit::WebColor color) { 428 layer_tree_host_->set_background_color(color); 429 } 430 431 void RenderWidgetCompositor::setHasTransparentBackground(bool transparent) { 432 layer_tree_host_->set_has_transparent_background(transparent); 433 } 434 435 void RenderWidgetCompositor::setVisible(bool visible) { 436 layer_tree_host_->SetVisible(visible); 437 } 438 439 void RenderWidgetCompositor::setPageScaleFactorAndLimits( 440 float page_scale_factor, float minimum, float maximum) { 441 layer_tree_host_->SetPageScaleFactorAndLimits( 442 page_scale_factor, minimum, maximum); 443 } 444 445 void RenderWidgetCompositor::startPageScaleAnimation( 446 const WebKit::WebPoint& destination, 447 bool use_anchor, 448 float new_page_scale, 449 double duration_sec) { 450 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( 451 duration_sec * base::Time::kMicrosecondsPerSecond); 452 layer_tree_host_->StartPageScaleAnimation( 453 gfx::Vector2d(destination.x, destination.y), 454 use_anchor, 455 new_page_scale, 456 duration); 457 } 458 459 void RenderWidgetCompositor::setNeedsAnimate() { 460 layer_tree_host_->SetNeedsAnimate(); 461 } 462 463 void RenderWidgetCompositor::setNeedsRedraw() { 464 if (threaded_) 465 layer_tree_host_->SetNeedsAnimate(); 466 else 467 widget_->scheduleAnimation(); 468 } 469 470 bool RenderWidgetCompositor::commitRequested() const { 471 return layer_tree_host_->CommitRequested(); 472 } 473 474 void RenderWidgetCompositor::didStopFlinging() { 475 layer_tree_host_->DidStopFlinging(); 476 } 477 478 void RenderWidgetCompositor::registerForAnimations(WebKit::WebLayer* layer) { 479 cc::Layer* cc_layer = static_cast<webkit::WebLayerImpl*>(layer)->layer(); 480 cc_layer->layer_animation_controller()->SetAnimationRegistrar( 481 layer_tree_host_->animation_registrar()); 482 } 483 484 bool RenderWidgetCompositor::compositeAndReadback( 485 void *pixels, const WebRect& rect_in_device_viewport) { 486 return layer_tree_host_->CompositeAndReadback(pixels, 487 rect_in_device_viewport); 488 } 489 490 void RenderWidgetCompositor::finishAllRendering() { 491 layer_tree_host_->FinishAllRendering(); 492 } 493 494 void RenderWidgetCompositor::setDeferCommits(bool defer_commits) { 495 layer_tree_host_->SetDeferCommits(defer_commits); 496 } 497 498 void RenderWidgetCompositor::setShowFPSCounter(bool show) { 499 cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state(); 500 debug_state.show_fps_counter = show; 501 layer_tree_host_->SetDebugState(debug_state); 502 } 503 504 void RenderWidgetCompositor::setShowPaintRects(bool show) { 505 cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state(); 506 debug_state.show_paint_rects = show; 507 layer_tree_host_->SetDebugState(debug_state); 508 } 509 510 void RenderWidgetCompositor::setShowDebugBorders(bool show) { 511 cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state(); 512 debug_state.show_debug_borders = show; 513 layer_tree_host_->SetDebugState(debug_state); 514 } 515 516 void RenderWidgetCompositor::setContinuousPaintingEnabled(bool enabled) { 517 cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state(); 518 debug_state.continuous_painting = enabled; 519 layer_tree_host_->SetDebugState(debug_state); 520 } 521 522 void RenderWidgetCompositor::setShowScrollBottleneckRects(bool show) { 523 cc::LayerTreeDebugState debug_state = layer_tree_host_->debug_state(); 524 debug_state.show_touch_event_handler_rects = show; 525 debug_state.show_wheel_event_handler_rects = show; 526 debug_state.show_non_fast_scrollable_rects = show; 527 layer_tree_host_->SetDebugState(debug_state); 528 } 529 530 void RenderWidgetCompositor::WillBeginFrame() { 531 widget_->InstrumentWillBeginFrame(); 532 widget_->willBeginCompositorFrame(); 533 } 534 535 void RenderWidgetCompositor::DidBeginFrame() { 536 widget_->InstrumentDidBeginFrame(); 537 } 538 539 void RenderWidgetCompositor::Animate(double frame_begin_time) { 540 widget_->webwidget()->animate(frame_begin_time); 541 } 542 543 void RenderWidgetCompositor::Layout() { 544 widget_->webwidget()->layout(); 545 } 546 547 void RenderWidgetCompositor::ApplyScrollAndScale(gfx::Vector2d scroll_delta, 548 float page_scale) { 549 widget_->webwidget()->applyScrollAndScale(scroll_delta, page_scale); 550 } 551 552 scoped_ptr<cc::OutputSurface> RenderWidgetCompositor::CreateOutputSurface( 553 bool fallback) { 554 return widget_->CreateOutputSurface(fallback); 555 } 556 557 void RenderWidgetCompositor::DidInitializeOutputSurface(bool success) { 558 if (!success) 559 widget_->webwidget()->didExitCompositingMode(); 560 } 561 562 void RenderWidgetCompositor::WillCommit() { 563 widget_->InstrumentWillComposite(); 564 } 565 566 void RenderWidgetCompositor::DidCommit() { 567 widget_->DidCommitCompositorFrame(); 568 widget_->didBecomeReadyForAdditionalInput(); 569 } 570 571 void RenderWidgetCompositor::DidCommitAndDrawFrame() { 572 widget_->didCommitAndDrawCompositorFrame(); 573 } 574 575 void RenderWidgetCompositor::DidCompleteSwapBuffers() { 576 widget_->didCompleteSwapBuffers(); 577 } 578 579 void RenderWidgetCompositor::ScheduleComposite() { 580 if (!suppress_schedule_composite_) 581 widget_->scheduleComposite(); 582 } 583 584 scoped_refptr<cc::ContextProvider> 585 RenderWidgetCompositor::OffscreenContextProviderForMainThread() { 586 return RenderThreadImpl::current()->OffscreenContextProviderForMainThread(); 587 } 588 589 scoped_refptr<cc::ContextProvider> 590 RenderWidgetCompositor::OffscreenContextProviderForCompositorThread() { 591 return RenderThreadImpl::current()-> 592 OffscreenContextProviderForCompositorThread(); 593 } 594 595 } // namespace content 596