| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/render_thread_impl.h" | 5 #include "content/renderer/render_thread_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <map> | 9 #include <map> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 } | 259 } |
| 260 | 260 |
| 261 private: | 261 private: |
| 262 const std::string scheme_; | 262 const std::string scheme_; |
| 263 const std::string host_; | 263 const std::string host_; |
| 264 const double zoom_level_; | 264 const double zoom_level_; |
| 265 | 265 |
| 266 DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer); | 266 DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer); |
| 267 }; | 267 }; |
| 268 | 268 |
| 269 class CompositorRasterThread : public base::SimpleThread { | |
| 270 public: | |
| 271 CompositorRasterThread(cc::TaskGraphRunner* task_graph_runner, | |
| 272 const std::string& name_prefix, | |
| 273 base::SimpleThread::Options options) | |
| 274 : base::SimpleThread(name_prefix, options), | |
| 275 task_graph_runner_(task_graph_runner) {} | |
| 276 | |
| 277 // Overridden from base::SimpleThread: | |
| 278 void Run() override { task_graph_runner_->Run(); } | |
| 279 | |
| 280 private: | |
| 281 cc::TaskGraphRunner* task_graph_runner_; | |
| 282 | |
| 283 DISALLOW_COPY_AND_ASSIGN(CompositorRasterThread); | |
| 284 }; | |
| 285 | |
| 286 std::string HostToCustomHistogramSuffix(const std::string& host) { | 269 std::string HostToCustomHistogramSuffix(const std::string& host) { |
| 287 if (host == "mail.google.com") | 270 if (host == "mail.google.com") |
| 288 return ".gmail"; | 271 return ".gmail"; |
| 289 if (host == "docs.google.com" || host == "drive.google.com") | 272 if (host == "docs.google.com" || host == "drive.google.com") |
| 290 return ".docs"; | 273 return ".docs"; |
| 291 if (host == "plus.google.com") | 274 if (host == "plus.google.com") |
| 292 return ".plus"; | 275 return ".plus"; |
| 293 if (host == "inbox.google.com") | 276 if (host == "inbox.google.com") |
| 294 return ".inbox"; | 277 return ".inbox"; |
| 295 return std::string(); | 278 return std::string(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 attributes.shareResources = true; | 372 attributes.shareResources = true; |
| 390 attributes.depth = false; | 373 attributes.depth = false; |
| 391 attributes.stencil = false; | 374 attributes.stencil = false; |
| 392 attributes.antialias = false; | 375 attributes.antialias = false; |
| 393 attributes.noAutomaticFlushes = true; | 376 attributes.noAutomaticFlushes = true; |
| 394 return attributes; | 377 return attributes; |
| 395 } | 378 } |
| 396 | 379 |
| 397 } // namespace | 380 } // namespace |
| 398 | 381 |
| 382 class RasterWorkerPool : public base::SequencedTaskRunner, |
| 383 public base::DelegateSimpleThread::Delegate { |
| 384 public: |
| 385 RasterWorkerPool() |
| 386 : namespace_token_(task_graph_runner_.GetNamespaceToken()) {} |
| 387 |
| 388 void Start(int num_threads, |
| 389 const base::SimpleThread::Options& thread_options) { |
| 390 DCHECK(threads_.empty()); |
| 391 while (threads_.size() < static_cast<size_t>(num_threads)) { |
| 392 scoped_ptr<base::DelegateSimpleThread> thread( |
| 393 new base::DelegateSimpleThread( |
| 394 this, base::StringPrintf( |
| 395 "CompositorTileWorker%u", |
| 396 static_cast<unsigned>(threads_.size() + 1)).c_str(), |
| 397 thread_options)); |
| 398 thread->Start(); |
| 399 threads_.push_back(thread.Pass()); |
| 400 } |
| 401 } |
| 402 |
| 403 void Shutdown() { |
| 404 // Shutdown raster threads. |
| 405 task_graph_runner_.Shutdown(); |
| 406 while (!threads_.empty()) { |
| 407 threads_.back()->Join(); |
| 408 threads_.pop_back(); |
| 409 } |
| 410 } |
| 411 |
| 412 // Overridden from base::TaskRunner: |
| 413 bool PostDelayedTask(const tracked_objects::Location& from_here, |
| 414 const base::Closure& task, |
| 415 base::TimeDelta delay) override { |
| 416 return PostNonNestableDelayedTask(from_here, task, delay); |
| 417 } |
| 418 |
| 419 bool RunsTasksOnCurrentThread() const override { return true; } |
| 420 |
| 421 // Overridden from base::SequencedTaskRunner: |
| 422 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here, |
| 423 const base::Closure& task, |
| 424 base::TimeDelta delay) override { |
| 425 base::AutoLock lock(lock_); |
| 426 DCHECK(!threads_.empty()); |
| 427 |
| 428 // Remove completed tasks. |
| 429 DCHECK(completed_tasks_.empty()); |
| 430 task_graph_runner_.CollectCompletedTasks(namespace_token_, |
| 431 &completed_tasks_); |
| 432 DCHECK_LE(completed_tasks_.size(), tasks_.size()); |
| 433 DCHECK(std::equal(completed_tasks_.begin(), completed_tasks_.end(), |
| 434 tasks_.begin())); |
| 435 tasks_.erase(tasks_.begin(), tasks_.begin() + completed_tasks_.size()); |
| 436 completed_tasks_.clear(); |
| 437 |
| 438 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
| 439 |
| 440 graph_.Reset(); |
| 441 for (const auto& task : tasks_) { |
| 442 cc::TaskGraph::Node node(task.get(), 0, graph_.nodes.size()); |
| 443 if (graph_.nodes.size()) { |
| 444 graph_.edges.push_back( |
| 445 cc::TaskGraph::Edge(graph_.nodes.back().task, node.task)); |
| 446 } |
| 447 graph_.nodes.push_back(node); |
| 448 } |
| 449 |
| 450 task_graph_runner_.ScheduleTasks(namespace_token_, &graph_); |
| 451 return true; |
| 452 } |
| 453 |
| 454 // Overridden from base::DelegateSimpleThread::Delegate: |
| 455 void Run() override { task_graph_runner_.Run(); } |
| 456 |
| 457 cc::TaskGraphRunner* GetTaskGraphRunner() { return &task_graph_runner_; } |
| 458 |
| 459 protected: |
| 460 ~RasterWorkerPool() override {} |
| 461 |
| 462 private: |
| 463 // Simple Task for the TaskGraphRunner that wraps a closure. |
| 464 class ClosureTask : public cc::Task { |
| 465 public: |
| 466 ClosureTask(const base::Closure& closure) : closure_(closure) {} |
| 467 |
| 468 // Overridden from cc::Task: |
| 469 void RunOnWorkerThread() override { |
| 470 closure_.Run(); |
| 471 closure_.Reset(); |
| 472 }; |
| 473 |
| 474 protected: |
| 475 ~ClosureTask() override {} |
| 476 |
| 477 private: |
| 478 base::Closure closure_; |
| 479 |
| 480 DISALLOW_COPY_AND_ASSIGN(ClosureTask); |
| 481 }; |
| 482 |
| 483 // The actual threads where work is done. |
| 484 ScopedVector<base::DelegateSimpleThread> threads_; |
| 485 cc::TaskGraphRunner task_graph_runner_; |
| 486 |
| 487 // Namespace where the SequencedTaskRunner tasks run. |
| 488 const cc::NamespaceToken namespace_token_; |
| 489 |
| 490 // Lock to exclusively access all the following members that are used to |
| 491 // implement the SequencedTaskRunner interface. |
| 492 base::Lock lock_; |
| 493 // List of tasks currently queued up for execution. |
| 494 ClosureTask::Vector tasks_; |
| 495 // Cached vector to avoid allocation when getting the list of complete tasks. |
| 496 ClosureTask::Vector completed_tasks_; |
| 497 // Graph object used for scheduling tasks. |
| 498 cc::TaskGraph graph_; |
| 499 }; |
| 500 |
| 399 // For measuring memory usage after each task. Behind a command line flag. | 501 // For measuring memory usage after each task. Behind a command line flag. |
| 400 class MemoryObserver : public base::MessageLoop::TaskObserver { | 502 class MemoryObserver : public base::MessageLoop::TaskObserver { |
| 401 public: | 503 public: |
| 402 MemoryObserver() {} | 504 MemoryObserver() {} |
| 403 ~MemoryObserver() override {} | 505 ~MemoryObserver() override {} |
| 404 | 506 |
| 405 void WillProcessTask(const base::PendingTask& pending_task) override {} | 507 void WillProcessTask(const base::PendingTask& pending_task) override {} |
| 406 | 508 |
| 407 void DidProcessTask(const base::PendingTask& pending_task) override { | 509 void DidProcessTask(const base::PendingTask& pending_task) override { |
| 408 LOCAL_HISTOGRAM_MEMORY_KB("Memory.RendererUsed", GetMemoryUsageKB()); | 510 LOCAL_HISTOGRAM_MEMORY_KB("Memory.RendererUsed", GetMemoryUsageKB()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 } | 558 } |
| 457 | 559 |
| 458 RenderThreadImpl* RenderThreadImpl::current() { | 560 RenderThreadImpl* RenderThreadImpl::current() { |
| 459 return lazy_tls.Pointer()->Get(); | 561 return lazy_tls.Pointer()->Get(); |
| 460 } | 562 } |
| 461 | 563 |
| 462 RenderThreadImpl::RenderThreadImpl(const InProcessChildThreadParams& params) | 564 RenderThreadImpl::RenderThreadImpl(const InProcessChildThreadParams& params) |
| 463 : ChildThreadImpl(Options::Builder() | 565 : ChildThreadImpl(Options::Builder() |
| 464 .InBrowserProcess(params) | 566 .InBrowserProcess(params) |
| 465 .UseMojoChannel(ShouldUseMojoChannel()) | 567 .UseMojoChannel(ShouldUseMojoChannel()) |
| 466 .Build()) { | 568 .Build()), |
| 569 raster_worker_pool_(new RasterWorkerPool()) { |
| 467 Init(); | 570 Init(); |
| 468 } | 571 } |
| 469 | 572 |
| 470 // When we run plugins in process, we actually run them on the render thread, | 573 // When we run plugins in process, we actually run them on the render thread, |
| 471 // which means that we need to make the render thread pump UI events. | 574 // which means that we need to make the render thread pump UI events. |
| 472 RenderThreadImpl::RenderThreadImpl( | 575 RenderThreadImpl::RenderThreadImpl( |
| 473 scoped_ptr<base::MessageLoop> main_message_loop) | 576 scoped_ptr<base::MessageLoop> main_message_loop) |
| 474 : ChildThreadImpl(Options::Builder() | 577 : ChildThreadImpl(Options::Builder() |
| 475 .UseMojoChannel(ShouldUseMojoChannel()) | 578 .UseMojoChannel(ShouldUseMojoChannel()) |
| 476 .Build()), | 579 .Build()), |
| 477 main_message_loop_(main_message_loop.Pass()) { | 580 main_message_loop_(main_message_loop.Pass()), |
| 581 raster_worker_pool_(new RasterWorkerPool()) { |
| 478 Init(); | 582 Init(); |
| 479 } | 583 } |
| 480 | 584 |
| 481 void RenderThreadImpl::Init() { | 585 void RenderThreadImpl::Init() { |
| 482 TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, ""); | 586 TRACE_EVENT_BEGIN_ETW("RenderThreadImpl::Init", 0, ""); |
| 483 | 587 |
| 484 base::trace_event::TraceLog::GetInstance()->SetThreadSortIndex( | 588 base::trace_event::TraceLog::GetInstance()->SetThreadSortIndex( |
| 485 base::PlatformThread::CurrentId(), | 589 base::PlatformThread::CurrentId(), |
| 486 kTraceEventRendererMainThreadSortIndex); | 590 kTraceEventRendererMainThreadSortIndex); |
| 487 | 591 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 is_distance_field_text_enabled_ = false; | 744 is_distance_field_text_enabled_ = false; |
| 641 } | 745 } |
| 642 | 746 |
| 643 // Note that under Linux, the media library will normally already have | 747 // Note that under Linux, the media library will normally already have |
| 644 // been initialized by the Zygote before this instance became a Renderer. | 748 // been initialized by the Zygote before this instance became a Renderer. |
| 645 media::InitializeMediaLibrary(); | 749 media::InitializeMediaLibrary(); |
| 646 | 750 |
| 647 memory_pressure_listener_.reset(new base::MemoryPressureListener( | 751 memory_pressure_listener_.reset(new base::MemoryPressureListener( |
| 648 base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this)))); | 752 base::Bind(&RenderThreadImpl::OnMemoryPressure, base::Unretained(this)))); |
| 649 | 753 |
| 650 compositor_task_graph_runner_.reset(new cc::TaskGraphRunner); | |
| 651 | |
| 652 is_gather_pixel_refs_enabled_ = false; | 754 is_gather_pixel_refs_enabled_ = false; |
| 653 | 755 |
| 654 int num_raster_threads = 0; | 756 int num_raster_threads = 0; |
| 655 std::string string_value = | 757 std::string string_value = |
| 656 command_line.GetSwitchValueASCII(switches::kNumRasterThreads); | 758 command_line.GetSwitchValueASCII(switches::kNumRasterThreads); |
| 657 bool parsed_num_raster_threads = | 759 bool parsed_num_raster_threads = |
| 658 base::StringToInt(string_value, &num_raster_threads); | 760 base::StringToInt(string_value, &num_raster_threads); |
| 659 DCHECK(parsed_num_raster_threads) << string_value; | 761 DCHECK(parsed_num_raster_threads) << string_value; |
| 660 DCHECK_GT(num_raster_threads, 0); | 762 DCHECK_GT(num_raster_threads, 0); |
| 661 | 763 |
| 662 // Note: Currently, gathering of pixel refs when using a single | 764 // Note: Currently, gathering of pixel refs when using a single |
| 663 // raster thread doesn't provide any benefit. This might change | 765 // raster thread doesn't provide any benefit. This might change |
| 664 // in the future but we avoid it for now to reduce the cost of | 766 // in the future but we avoid it for now to reduce the cost of |
| 665 // Picture::Create. | 767 // Picture::Create. |
| 666 is_gather_pixel_refs_enabled_ = num_raster_threads > 1; | 768 is_gather_pixel_refs_enabled_ = num_raster_threads > 1; |
| 667 | 769 |
| 668 base::SimpleThread::Options thread_options; | 770 base::SimpleThread::Options thread_options; |
| 669 #if defined(OS_ANDROID) || defined(OS_LINUX) | 771 #if defined(OS_ANDROID) || defined(OS_LINUX) |
| 670 if (!command_line.HasSwitch( | 772 if (!command_line.HasSwitch( |
| 671 switches::kUseNormalPriorityForTileTaskWorkerThreads)) { | 773 switches::kUseNormalPriorityForTileTaskWorkerThreads)) { |
| 672 thread_options.set_priority(base::ThreadPriority::BACKGROUND); | 774 thread_options.set_priority(base::ThreadPriority::BACKGROUND); |
| 673 } | 775 } |
| 674 #endif | 776 #endif |
| 675 while (compositor_raster_threads_.size() < | 777 |
| 676 static_cast<size_t>(num_raster_threads)) { | 778 raster_worker_pool_->Start(num_raster_threads, thread_options); |
| 677 scoped_ptr<CompositorRasterThread> raster_thread(new CompositorRasterThread( | |
| 678 compositor_task_graph_runner_.get(), | |
| 679 base::StringPrintf("CompositorTileWorker%u", | |
| 680 static_cast<unsigned>( | |
| 681 compositor_raster_threads_.size() + 1)).c_str(), | |
| 682 thread_options)); | |
| 683 raster_thread->Start(); | |
| 684 compositor_raster_threads_.push_back(raster_thread.Pass()); | |
| 685 } | |
| 686 | 779 |
| 687 // TODO(boliu): In single process, browser main loop should set up the | 780 // TODO(boliu): In single process, browser main loop should set up the |
| 688 // discardable memory manager, and should skip this if kSingleProcess. | 781 // discardable memory manager, and should skip this if kSingleProcess. |
| 689 // See crbug.com/503724. | 782 // See crbug.com/503724. |
| 690 base::DiscardableMemoryAllocator::SetInstance( | 783 base::DiscardableMemoryAllocator::SetInstance( |
| 691 ChildThreadImpl::discardable_shared_memory_manager()); | 784 ChildThreadImpl::discardable_shared_memory_manager()); |
| 692 | 785 |
| 693 service_registry()->AddService<RenderFrameSetup>( | 786 service_registry()->AddService<RenderFrameSetup>( |
| 694 base::Bind(CreateRenderFrameSetup)); | 787 base::Bind(CreateRenderFrameSetup)); |
| 695 | 788 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 } | 847 } |
| 755 | 848 |
| 756 media_thread_.reset(); | 849 media_thread_.reset(); |
| 757 | 850 |
| 758 // AudioMessageFilter may be accessed on |media_thread_|, so shutdown after. | 851 // AudioMessageFilter may be accessed on |media_thread_|, so shutdown after. |
| 759 RemoveFilter(audio_message_filter_.get()); | 852 RemoveFilter(audio_message_filter_.get()); |
| 760 audio_message_filter_ = NULL; | 853 audio_message_filter_ = NULL; |
| 761 | 854 |
| 762 compositor_thread_.reset(); | 855 compositor_thread_.reset(); |
| 763 | 856 |
| 764 // Shutdown raster threads. | 857 raster_worker_pool_->Shutdown(); |
| 765 compositor_task_graph_runner_->Shutdown(); | |
| 766 while (!compositor_raster_threads_.empty()) { | |
| 767 compositor_raster_threads_.back()->Join(); | |
| 768 compositor_raster_threads_.pop_back(); | |
| 769 } | |
| 770 compositor_task_graph_runner_.reset(); | |
| 771 | 858 |
| 772 main_input_callback_.Cancel(); | 859 main_input_callback_.Cancel(); |
| 773 input_handler_manager_.reset(); | 860 input_handler_manager_.reset(); |
| 774 if (input_event_filter_.get()) { | 861 if (input_event_filter_.get()) { |
| 775 RemoveFilter(input_event_filter_.get()); | 862 RemoveFilter(input_event_filter_.get()); |
| 776 input_event_filter_ = NULL; | 863 input_event_filter_ = NULL; |
| 777 } | 864 } |
| 778 | 865 |
| 779 // RemoveEmbeddedWorkerRoute may be called while deleting | 866 // RemoveEmbeddedWorkerRoute may be called while deleting |
| 780 // EmbeddedWorkerDispatcher. So it must be deleted before deleting | 867 // EmbeddedWorkerDispatcher. So it must be deleted before deleting |
| (...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 if (SynchronousCompositorFactory* factory = | 1540 if (SynchronousCompositorFactory* factory = |
| 1454 SynchronousCompositorFactory::GetInstance()) { | 1541 SynchronousCompositorFactory::GetInstance()) { |
| 1455 return factory->CreateExternalBeginFrameSource(routing_id); | 1542 return factory->CreateExternalBeginFrameSource(routing_id); |
| 1456 } | 1543 } |
| 1457 #endif | 1544 #endif |
| 1458 return make_scoped_ptr(new CompositorExternalBeginFrameSource( | 1545 return make_scoped_ptr(new CompositorExternalBeginFrameSource( |
| 1459 compositor_message_filter_.get(), sync_message_filter(), routing_id)); | 1546 compositor_message_filter_.get(), sync_message_filter(), routing_id)); |
| 1460 } | 1547 } |
| 1461 | 1548 |
| 1462 cc::TaskGraphRunner* RenderThreadImpl::GetTaskGraphRunner() { | 1549 cc::TaskGraphRunner* RenderThreadImpl::GetTaskGraphRunner() { |
| 1463 return compositor_task_graph_runner_.get(); | 1550 return raster_worker_pool_->GetTaskGraphRunner(); |
| 1464 } | 1551 } |
| 1465 | 1552 |
| 1466 bool RenderThreadImpl::IsGatherPixelRefsEnabled() { | 1553 bool RenderThreadImpl::IsGatherPixelRefsEnabled() { |
| 1467 return is_gather_pixel_refs_enabled_; | 1554 return is_gather_pixel_refs_enabled_; |
| 1468 } | 1555 } |
| 1469 | 1556 |
| 1470 bool RenderThreadImpl::IsMainThread() { | 1557 bool RenderThreadImpl::IsMainThread() { |
| 1471 return !!current(); | 1558 return !!current(); |
| 1472 } | 1559 } |
| 1473 | 1560 |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1790 media_thread_->Start(); | 1877 media_thread_->Start(); |
| 1791 | 1878 |
| 1792 #if defined(OS_ANDROID) | 1879 #if defined(OS_ANDROID) |
| 1793 renderer_demuxer_ = new RendererDemuxerAndroid(); | 1880 renderer_demuxer_ = new RendererDemuxerAndroid(); |
| 1794 AddFilter(renderer_demuxer_.get()); | 1881 AddFilter(renderer_demuxer_.get()); |
| 1795 #endif | 1882 #endif |
| 1796 } | 1883 } |
| 1797 return media_thread_->task_runner(); | 1884 return media_thread_->task_runner(); |
| 1798 } | 1885 } |
| 1799 | 1886 |
| 1887 base::SequencedTaskRunner* RenderThreadImpl::GetWorkerSequencedTaskRunner() { |
| 1888 return raster_worker_pool_.get(); |
| 1889 } |
| 1890 |
| 1800 void RenderThreadImpl::SampleGamepads(blink::WebGamepads* data) { | 1891 void RenderThreadImpl::SampleGamepads(blink::WebGamepads* data) { |
| 1801 blink_platform_impl_->sampleGamepads(*data); | 1892 blink_platform_impl_->sampleGamepads(*data); |
| 1802 } | 1893 } |
| 1803 | 1894 |
| 1804 bool RenderThreadImpl::RendererIsHidden() const { | 1895 bool RenderThreadImpl::RendererIsHidden() const { |
| 1805 return widget_count_ > 0 && hidden_widget_count_ == widget_count_; | 1896 return widget_count_ > 0 && hidden_widget_count_ == widget_count_; |
| 1806 } | 1897 } |
| 1807 | 1898 |
| 1808 void RenderThreadImpl::WidgetCreated() { | 1899 void RenderThreadImpl::WidgetCreated() { |
| 1809 bool renderer_was_hidden = RendererIsHidden(); | 1900 bool renderer_was_hidden = RendererIsHidden(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1880 } | 1971 } |
| 1881 | 1972 |
| 1882 void RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError() { | 1973 void RenderThreadImpl::PendingRenderFrameConnect::OnConnectionError() { |
| 1883 size_t erased = | 1974 size_t erased = |
| 1884 RenderThreadImpl::current()->pending_render_frame_connects_.erase( | 1975 RenderThreadImpl::current()->pending_render_frame_connects_.erase( |
| 1885 routing_id_); | 1976 routing_id_); |
| 1886 DCHECK_EQ(1u, erased); | 1977 DCHECK_EQ(1u, erased); |
| 1887 } | 1978 } |
| 1888 | 1979 |
| 1889 } // namespace content | 1980 } // namespace content |
| OLD | NEW |